Compare commits
3 Commits
main
...
elastic_se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4a322ed5d | ||
|
|
6dc7e5ac27 | ||
|
|
09bbc04959 |
@@ -1,33 +0,0 @@
|
||||
---
|
||||
# .ansible-lint
|
||||
|
||||
# Specify exclude paths to prevent linting vendor roles, etc.
|
||||
exclude_paths:
|
||||
- ./.git/
|
||||
- ./.venv/
|
||||
- ./galaxy_roles/
|
||||
|
||||
# A list of rules to skip. This is a more modern and readable alternative to 'skip_list'.
|
||||
skip_list:
|
||||
- experimental
|
||||
- fqcn-builtins
|
||||
- no-handler
|
||||
- var-naming
|
||||
- no-changed-when
|
||||
- risky-shell-pipe
|
||||
|
||||
# Enforce certain rules that are not enabled by default.
|
||||
enable_list:
|
||||
- no-free-form
|
||||
- var-spacing
|
||||
- no-log-password
|
||||
- no-relative-path
|
||||
- command-instead-of-module
|
||||
- fqcn[deep]
|
||||
- no-changed-when
|
||||
|
||||
# Offline mode disables any features that require internet access.
|
||||
offline: false
|
||||
|
||||
# Set the desired verbosity level.
|
||||
verbosity: 1
|
||||
@@ -1,17 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
8
.gitattributes
vendored
8
.gitattributes
vendored
@@ -1,8 +0,0 @@
|
||||
vars/group_vars/proxmox/secrets_vm.yml diff=ansible-vault merge=binary
|
||||
vars/group_vars/all/secrets.yml diff=ansible-vault merge=binary
|
||||
vars/group_vars/docker/secrets.yml diff=ansible-vault merge=binary
|
||||
vars/group_vars/k3s/secrets.yml diff=ansible-vault merge=binary
|
||||
vars/group_vars/k3s/secrets_token.yml diff=ansible-vault merge=binary
|
||||
vars/group_vars/kubernetes/secrets.yml diff=ansible-vault merge=binary
|
||||
vars/group_vars/proxmox/secrets.yml diff=ansible-vault merge=binary
|
||||
vars/group_vars/proxmox/secrets_vm.yml diff=ansible-vault merge=binary
|
||||
45
.github/workflows/ci.yaml
vendored
45
.github/workflows/ci.yaml
vendored
@@ -1,45 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install ansible-lint==6.22.2 ansible-core==2.15.8
|
||||
|
||||
- name: Install Ansible collections
|
||||
run: ansible-galaxy collection install -r requirements.yaml
|
||||
|
||||
- name: Run ansible-lint
|
||||
run: ansible-lint
|
||||
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install pre-commit
|
||||
run: pip install pre-commit
|
||||
|
||||
- name: Run pre-commit
|
||||
run: pre-commit run --all-files
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +0,0 @@
|
||||
.worktrees/
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.6.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: ansible-galaxy-install
|
||||
name: Install ansible-galaxy collections
|
||||
entry: ansible-galaxy collection install -r requirements.yaml
|
||||
language: system
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
- repo: https://github.com/ansible/ansible-lint
|
||||
rev: v6.22.2
|
||||
hooks:
|
||||
- id: ansible-lint
|
||||
files: \.(yaml)$
|
||||
additional_dependencies:
|
||||
- ansible-core==2.15.8
|
||||
130
README.md
130
README.md
@@ -1,82 +1,74 @@
|
||||
# TuDatTr IaC
|
||||
|
||||
**I do not recommend this project being used for one's own infrastructure, as this project is heavily attuned to my specific host/network setup.**
|
||||
**I do not recommend this project being used for ones own infrastructure, as
|
||||
this project is heavily attuned to my specific host/network setup**
|
||||
The Ansible Project to provision fresh Debian VMs for my Proxmox instances.
|
||||
Some values are hard coded such as the public key both in
|
||||
[./scripts/debian_seed.sh](./scripts/debian_seed.sh) and [./group_vars/all/vars.yml](./group_vars/all/vars.yml).
|
||||
|
||||
This Ansible project automates the setup of a K3s Kubernetes cluster on Proxmox VE. It also includes playbooks for configuring Docker hosts, load balancers, and other services.
|
||||
## Prerequisites
|
||||
|
||||
## Repository Structure
|
||||
- [secrets.yml](secrets.yml) in the root directory of this repository.
|
||||
Skeleton file can be found as [./secrets.yml.skeleton](./secrets.yml.skeleton).
|
||||
- IP Configuration of hosts like in [./host_vars/\*](./host_vars/*)
|
||||
- Setup [~/.ssh/config](~/.ssh/config) for the respective hosts used.
|
||||
- Install `passlib` for your operating system. Needed to hash passwords ad-hoc.
|
||||
|
||||
The repository is organized into the following main directories:
|
||||
## Improvable Variables
|
||||
|
||||
- `playbooks/`: Contains the main Ansible playbooks for different setup scenarios.
|
||||
- `roles/`: Contains the Ansible roles that are used by the playbooks.
|
||||
- `vars/`: Contains variable files, including group-specific variables.
|
||||
- `group_vars/k3s/vars.yml`:
|
||||
- `k3s.server.ips`: Take list of IPs from host_vars `k3s_server*.yml`.
|
||||
- `k3s_db_connection_string`: Embed this variable in the `k3s.db.`-directory.
|
||||
Currently causes loop.
|
||||
|
||||
## Playbooks
|
||||
## Run Playbook
|
||||
|
||||
The following playbooks are available:
|
||||
To run a first playbook and test the setup the following command can be executed.
|
||||
|
||||
- `proxmox.yml`: Provisions VMs and containers on Proxmox VE.
|
||||
- `k3s-servers.yml`: Sets up the K3s master nodes.
|
||||
- `k3s-agents.yml`: Sets up the K3s agent nodes.
|
||||
- `k3s-loadbalancer.yml`: Configures a load balancer for the K3s cluster.
|
||||
- `k3s-storage.yml`: Configures storage for the K3s cluster.
|
||||
- `docker.yml`: Sets up Docker hosts and their load balancer.
|
||||
- `docker-host.yml`: Configures the docker hosts.
|
||||
- `docker-lb.yml`: Configures a load balancer for Docker services.
|
||||
- `kubernetes_setup.yml`: A meta-playbook for setting up the entire Kubernetes cluster.
|
||||
|
||||
## Roles
|
||||
|
||||
The following roles are defined:
|
||||
|
||||
- `common`: Common configuration tasks for all nodes.
|
||||
- `proxmox`: Manages Proxmox VE, including VM and container creation.
|
||||
- `k3s_server`: Installs and configures K3s master nodes.
|
||||
- `k3s_agent`: Installs and configures K3s agent nodes.
|
||||
- `k3s_loadbalancer`: Configures an Nginx-based load balancer for the K3s cluster.
|
||||
- `k3s_storage`: Configures storage solutions for Kubernetes.
|
||||
- `docker_host`: Installs and configures Docker.
|
||||
- `kubernetes_argocd`: Deploys Argo CD to the Kubernetes cluster.
|
||||
- `node_exporter`: Installs the Prometheus Node Exporter for monitoring.
|
||||
- `reverse_proxy`: Configures a Caddy-based reverse proxy.
|
||||
- `edge_vps`: Placeholder role for Edge VPS configuration.
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Install dependencies:**
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
ansible-galaxy install -r requirements.yml
|
||||
```
|
||||
|
||||
2. **Configure variables:**
|
||||
|
||||
- Create an inventory file (e.g., `vars/k3s.ini`).
|
||||
- Adjust variables in `vars/group_vars/` to match your environment.
|
||||
|
||||
3. **Run playbooks:**
|
||||
|
||||
```bash
|
||||
# To provision VMs on Proxmox
|
||||
ansible-playbook -i vars/proxmox.ini playbooks/proxmox.yml
|
||||
|
||||
# To set up the K3s cluster
|
||||
ansible-playbook -i vars/k3s.ini playbooks/kubernetes_setup.yml
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
### Vault Git Diff
|
||||
|
||||
This repo has a `.gitattributes` which points at the repos ansible-vault files.
|
||||
These can be temporarily decrypted for git diff by adding this in conjunction with the `.gitattributes`:
|
||||
```sh
|
||||
# https://stackoverflow.com/questions/29937195/how-to-diff-ansible-vault-changes
|
||||
git config --global diff.ansible-vault.textconv "ansible-vault view"
|
||||
ansible-playbook -i production -J k3s-servers.yml
|
||||
```
|
||||
|
||||
## Disclaimer
|
||||
This will run the [./k3s-servers.yml](./k3s-servers.yml) playbook and execute
|
||||
its roles.
|
||||
|
||||
This project is highly customized for the author's specific environment. Using it without modification is not recommended.
|
||||
## After successful k3s installation
|
||||
|
||||
To access our Kubernetes cluster from our host machine to work on it via
|
||||
flux and such we need to manually copy a k3s config from one of our server nodes to our host machine.
|
||||
Then we need to install `kubectl` on our host machine and optionally `kubectx` if we're already
|
||||
managing other Kubernetes instances.
|
||||
Then we replace the localhost address inside of the config with the IP of our load balancer.
|
||||
Finally we'll need to set the KUBECONFIG variable.
|
||||
|
||||
```sh
|
||||
mkdir ~/.kube/
|
||||
scp k3s-server00:/etc/rancher/k3s/k3s.yaml ~/.kube/config
|
||||
chown $USER ~/.kube/config
|
||||
sed -i "s/127.0.0.1/192.168.20.22/" ~/.kube/config
|
||||
export KUBECONFIG=~/.kube/config
|
||||
```
|
||||
|
||||
Install flux and continue in the flux repository.
|
||||
|
||||
## Longhorn Nodes
|
||||
|
||||
To create longhorn nodes from existing kubernetes nodes we want to increase
|
||||
their storage capacity. Since we're using VMs for our k3s nodes we can
|
||||
resize the root-disk of the VMs in the proxmox GUI.
|
||||
|
||||
Then we have to resize the partitions inside of the VM so the root partition
|
||||
uses the newly available space.
|
||||
When we have LVM-based root partition we can do the following:
|
||||
|
||||
```sh
|
||||
# Create a new partition from the free space.
|
||||
sudo fdisk /dev/sda
|
||||
# echo "n\n\n\n\n\nw\n"
|
||||
# n > 5x\n > w > \n
|
||||
# Create a LVM volume on the new partition
|
||||
sudo pvcreate /dev/sda3
|
||||
sudo vgextend k3s-vg /dev/sda3
|
||||
# Use the newly available storage in the root volume
|
||||
sudo lvresize -l +100%FREE -r /dev/k3s-vg/root
|
||||
```
|
||||
|
||||
31
Vagrantfile
vendored
Normal file
31
Vagrantfile
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "bento/ubuntu-24.04"
|
||||
config.vm.box_version = "202404.26.0"
|
||||
|
||||
# Configure VM provider resources (optional)
|
||||
config.vm.provider :virtualbox do |v|
|
||||
v.memory = 4096
|
||||
v.cpus = 2
|
||||
end
|
||||
|
||||
|
||||
config.vm.define "test" do |v|
|
||||
v.vm.hostname = "test"
|
||||
v.vm.network :private_network, ip: "192.168.56.123"
|
||||
|
||||
v.vm.provision "bootstrap", type: "shell" do |s|
|
||||
s.inline = "sudo apt install ansible -y"
|
||||
end
|
||||
#
|
||||
# Use Ansible for provisioning
|
||||
v.vm.provision "ansible" do |ansible|
|
||||
ansible.playbook = "playbook.yml" # Path to the Ansible playbook relative to the Vagrantfile
|
||||
ansible.inventory_path = "inventory" # Path to the inventory file
|
||||
# Extra vars can be defined if needed
|
||||
# ansible.extra_vars = { some_var: "value" }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
10
ansible.cfg
10
ansible.cfg
@@ -1,12 +1,9 @@
|
||||
[defaults]
|
||||
# (string) Path to the Python interpreter to be used for module execution on remote targets, or an automatic discovery mode. Supported discovery modes are ``auto`` (the default), ``auto_silent``, ``auto_legacy``, and ``auto_legacy_silent``. All discovery modes employ a lookup table to use the included system Python (on distributions known to include one), falling back to a fixed ordered list of well-known Python interpreter locations if a platform-specific default is not available. The fallback behavior will issue a warning that the interpreter should be set explicitly (since interpreters installed later may change which one is used). This warning behavior can be disabled by setting ``auto_silent`` or ``auto_legacy_silent``. The value of ``auto_legacy`` provides all the same behavior, but for backwards-compatibility with older Ansible releases that always defaulted to ``/usr/bin/python``, will use that interpreter if present.
|
||||
interpreter_python=python3
|
||||
|
||||
# (pathspec) Colon separated paths in which Ansible will search for Roles.
|
||||
roles_path=./roles
|
||||
|
||||
# (pathlist) Comma separated list of Ansible inventory sources
|
||||
inventory=./vars/
|
||||
inventory=./inventory/production
|
||||
|
||||
# (path) The vault password file to use. Equivalent to --vault-password-file or --vault-id
|
||||
# If executable, it will be run and the resulting stdout will be used as the password.
|
||||
@@ -14,7 +11,7 @@ vault_password_file=/media/veracrypt1/scripts/ansible_vault.sh
|
||||
|
||||
# (list) Check all of these extensions when looking for 'variable' files which should be YAML or JSON or vaulted versions of these.
|
||||
# This affects vars_files, include_vars, inventory and vars plugins among others.
|
||||
yaml_valid_extensions=.yaml
|
||||
yaml_valid_extensions=.yml
|
||||
|
||||
# (boolean) Set this to "False" if you want to avoid host key checking by the underlying tools Ansible uses to connect to the host
|
||||
host_key_checking=False
|
||||
@@ -36,6 +33,3 @@ skip=dark gray
|
||||
[tags]
|
||||
# (list) default list of tags to skip in your plays, has precedence over Run Tags
|
||||
;skip=
|
||||
|
||||
[inventory]
|
||||
ignore_extensions={{(REJECT_EXTS + ('.orig', '.cfg', '.retry', '.bak'))}}
|
||||
|
||||
@@ -688,3 +688,4 @@
|
||||
|
||||
# (list) default list of tags to skip in your plays, has precedence over Run Tags
|
||||
;skip=
|
||||
|
||||
|
||||
69
blog.md
69
blog.md
@@ -1,69 +0,0 @@
|
||||
---
|
||||
title: "Automating My Homelab: From Bare Metal to Kubernetes with Ansible"
|
||||
date: 2025-07-27
|
||||
author: "TuDatTr"
|
||||
tags: ["Ansible", "Proxmox", "Kubernetes", "K3s", "IaC", "Homelab"]
|
||||
---
|
||||
|
||||
## The Homelab: Repeatable, Automated, and Documented
|
||||
|
||||
For many tech enthusiasts, a homelab is a playground for learning, experimenting, and self-hosting services. But as the complexity grows, so does the management overhead. Manually setting up virtual machines, configuring networks, and deploying applications becomes a tedious and error-prone process. This lead me to building my homelab as Infrastructure as Code (IaC) with Ansible.
|
||||
|
||||
This blog post walks you through my Ansible project, which automates the entire lifecycle of my homelab—from provisioning VMs on Proxmox to deploying a production-ready K3s Kubernetes cluster.
|
||||
|
||||
## Why Ansible?
|
||||
|
||||
When I decided to automate my infrastructure, I considered several tools. I chose Ansible for its simplicity, agentless architecture, and gentle learning curve. Writing playbooks in YAML felt declarative and intuitive, and the vast collection of community-supported modules meant I wouldn't have to reinvent the wheel.
|
||||
|
||||
## The Architecture: A Multi-Layered Approach
|
||||
|
||||
My Ansible project is designed to be modular and scalable, with a clear separation of concerns. It's built around a collection of roles, each responsible for a specific component of the infrastructure.
|
||||
|
||||
### Layer 1: Proxmox Provisioning
|
||||
|
||||
The foundation of my homelab is Proxmox VE. The `proxmox` role is the first step in the automation pipeline. It handles:
|
||||
|
||||
- **VM and Container Creation:** Using a simple YAML definition in my `vars` files, I can specify the number of VMs and containers to create, their resources (CPU, memory, disk), and their base operating system images.
|
||||
- **Cloud-Init Integration:** For VMs, I leverage Cloud-Init to perform initial setup, such as setting the hostname, creating users, and injecting SSH keys for Ansible to connect to.
|
||||
- **Hardware Passthrough:** The role also configures hardware passthrough for devices like Intel Quick Sync for video transcoding in my media server.
|
||||
|
||||
### Layer 2: The K3s Kubernetes Cluster
|
||||
|
||||
With the base VMs ready, the next step is to build the Kubernetes cluster. I chose K3s for its lightweight footprint and ease of installation. The setup is divided into several roles:
|
||||
|
||||
- `k3s_server`: This role bootstraps the first master node and then adds additional master nodes to create a highly available control plane.
|
||||
- `k3s_agent`: This role joins the worker nodes to the cluster.
|
||||
- `k3s_loadbalancer`: A dedicated VM running Nginx is set up to act as a load balancer for the K3s API server, ensuring a stable endpoint for `kubectl` and other clients.
|
||||
|
||||
### Layer 3: Applications and Services
|
||||
|
||||
Once the Kubernetes cluster is up and running, it's time to deploy applications. My project includes roles for:
|
||||
|
||||
- `docker_host`: For services that are better suited to run in a traditional Docker environment, this role sets up and configures Docker hosts.
|
||||
- `kubernetes_argocd`: I use Argo CD for GitOps-based continuous delivery. This role deploys Argo CD to the cluster and configures it to sync with my application repositories.
|
||||
- `reverse_proxy`: Caddy is my reverse proxy of choice, and this role automates its installation and configuration, including obtaining SSL certificates from Let's Encrypt.
|
||||
|
||||
## Putting It All Together: The Power of Playbooks
|
||||
|
||||
The playbooks in the `playbooks/` directory tie everything together. For example, the `kubernetes_setup.yml` playbook runs all the necessary roles in the correct order to bring up the entire Kubernetes cluster from scratch.
|
||||
|
||||
```yaml
|
||||
# playbooks/kubernetes_setup.yml
|
||||
---
|
||||
- name: Set up Kubernetes Cluster
|
||||
hosts: all
|
||||
gather_facts: true
|
||||
roles:
|
||||
- role: k3s_server
|
||||
- role: k3s_agent
|
||||
- role: k3s_loadbalancer
|
||||
- role: kubernetes_argocd
|
||||
```
|
||||
|
||||
## Final Thoughts and Future Plans
|
||||
|
||||
This Ansible project has transformed my homelab from a collection of manually configured machines into a fully automated and reproducible environment. I can now tear down and rebuild my entire infrastructure with a single command, which gives me the confidence to experiment without fear of breaking things.
|
||||
|
||||
While the project is highly tailored to my specific needs, I hope this overview provides some inspiration for your own automation journey. The principles of IaC and the power of tools like Ansible can be applied to any environment, big or small.
|
||||
|
||||
What's next? I plan to explore more advanced Kubernetes concepts, such as Cilium for networking and policy, and integrate more of my self-hosted services into the GitOps workflow with Argo CD. The homelab is never truly "finished," and that's what makes it so much fun.
|
||||
75
changelog.md
75
changelog.md
@@ -1,75 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
Technical evolution of the infrastructure stack, tracking the migration from standalone Docker hosts to a fully automated, GitOps-managed Kubernetes cluster.
|
||||
|
||||
## Phase 5: GitOps & Cluster Hardening (July 2025 - Present)
|
||||
|
||||
*Shifted control plane management to ArgoCD and expanded storage capabilities.*
|
||||
|
||||
- **GitOps Implementation**:
|
||||
- Deployed **ArgoCD** in an App-of-Apps pattern to manage cluster state (`89c51aa`).
|
||||
- Integrated **Sealed Secrets** (implied via vault diffs) and **Cert-Manager** for automated TLS management (`76000f8`).
|
||||
- Migrated core services (Traefik, MetalLB) to Helm charts managed via ArgoCD manifests.
|
||||
- **Storage Architecture**:
|
||||
- Implemented **Longhorn** with iSCSI support for distributed block storage (`48aec11`).
|
||||
- Added **NFS Provisioner** (`e1a2248`) for ReadWriteMany volumes capabilities.
|
||||
- **Networking**:
|
||||
- Centralized primary server IP logic (`97a5d6c`) to support HA control plane capability.
|
||||
- Replaced Netcup DNS webhooks with **Cloudflare** for Caddy ACME challenges (`9cb90a8`).
|
||||
- **Observability**:
|
||||
- Added **healthcheck** definitions to Docker Compose services (`0e8e07e`) and K3s probes.
|
||||
|
||||
## Phase 4: IaaC Refactoring & Proxmox API Integration (Nov 2024 - June 2025)
|
||||
|
||||
*Refactored Ansible roles for modularity and implemented Proxmox API automation for "click-less" provisioning.*
|
||||
|
||||
- **Proxmox Automation**:
|
||||
- Developed `roles/proxmox` to interface with Proxmox API: automated VM creation, cloning from templates, and Cloud-Init injection (`f2ea03b`).
|
||||
- Configured **PCI Passthrough** (`591342f`) and hardware acceleration for media transcoding nodes.
|
||||
- Added cron-based VM state reconciliation (`a1da69a`).
|
||||
- **Ansible Restructuring**:
|
||||
- **Inventory Refactor**: Moved from root-level inventory files to a hierarchical `vars/` structure (`609e000`).
|
||||
- **Linting Pipeline**: Integrated `ansible-lint` and `pre-commit` hooks (`6eef96b`) to enforce YAML standards and best practices.
|
||||
- **Vault Security**: Configured `.gitattributes` to enable `ansible-vault view` for cleartext diffs in git (`c3905ed`).
|
||||
- **Identity Management**:
|
||||
- Deployed **Keycloak** (`42196a3`) for OIDC/SAML authentication across the stack.
|
||||
|
||||
## Phase 3: The Kubernetes Migration (Sep 2024 - Oct 2024)
|
||||
|
||||
*Architectural pivot from Docker Compose to K3s.*
|
||||
|
||||
- **Control Plane Setup**:
|
||||
- Bootstrapped **K3s** cluster with dedicated server/agent split.
|
||||
- Configured **HAProxy/Nginx** load balancers (`51a49d0`) for API server high availability.
|
||||
- **Node Provisioning**:
|
||||
- Standardized node bootstrapping (kernel modules, sysctl params) for K3s compatibility.
|
||||
- Deployed specialized storage nodes for Longhorn (`7d58de9`).
|
||||
- **Decommissioning**:
|
||||
- Drained and removed legacy Docker hosts (`0aed818`).
|
||||
- Migrated stateful workloads (Postgres) to cluster-managed resources.
|
||||
|
||||
## Phase 2: Docker Service Expansion (2023 - 2024)
|
||||
|
||||
*Vertical scaling of Docker hosts and introduction of the monitoring stack.*
|
||||
|
||||
- **Service Stack**:
|
||||
- Deployed the **\*arr suite** (Sonarr, Radarr, etc.) and Jellyfin with hardware mapping (`3d7f143`).
|
||||
- Integrated **Paperless-ngx** with Redis and Tika consumption (`3f88065`).
|
||||
- Self-hosted **Gitea** and **GitLab** (later removed) for source control.
|
||||
- **Observability V1**:
|
||||
- Deployed **Prometheus** and **Grafana** stack (`b3ae5ef`).
|
||||
- Added **Node Exporter** and **SmartCTL Exporter** (`0a361d9`) to bare metal hosts.
|
||||
- Implemented **Uptime Kuma** for external availability monitoring.
|
||||
- **Reverse Proxy**:
|
||||
- Transitioned ingress from Traefik v2 to **Nginx Proxy Manager**, then to **Caddy** for simpler configuration management (`a9af3c7`, `1a1b8cb`).
|
||||
|
||||
## Phase 1: Genesis & Networking (Late 2022)
|
||||
|
||||
*Initial infrastructure bring-up.*
|
||||
|
||||
- **Base Configuration**:
|
||||
- Established Ansible role structure for baseline system hardening (SSH, users, packages).
|
||||
- Configured **Wireguard** mesh for secure inter-node communication (`2ba4259`).
|
||||
- Set up **Backblaze B2** offsite backups via Restic/Rclone (`b371e24`).
|
||||
- **Network**:
|
||||
- Experimented with **macvlan** Docker networks for direct container IP assignment.
|
||||
56
group_vars/all/secrets.yml
Normal file
56
group_vars/all/secrets.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
34623331393561623539666362643966336661326136363431666465356535343663376236663066
|
||||
3235363061633666626133313363373336656438633566630a383230393161323862303863656464
|
||||
61633861323966343263363466343130306635343539326464363637383139343033656130336464
|
||||
3163373535613961340a643335626165306663363063656339653862393533633534366331336231
|
||||
63393432383731633463323164333831313535373261336166326237306230326465616239306536
|
||||
37663863663161393130373835373062393866633864373465333937633838303130386334356566
|
||||
64303663303862623038646235303934376230393538353466393232363764366339616633343433
|
||||
65343730663864393766313134653335396562646135306637613031333461613965666465376532
|
||||
32643261626665396338313836633337383932616265613662383132303539623239623965333966
|
||||
66333638643635313262616434396164313833303065303662303736303232346535613834643435
|
||||
32316434343231363662393163353832393166643739396165313631363539663439316133616361
|
||||
61623830613035396333303363383332653736666231343763353666356539633433373066613330
|
||||
65656631343764323234333161636632616130353139626362343361386535313336666566636464
|
||||
35323434656439346262336335383366626565333765343562633236636132636532333761663535
|
||||
31383565313436633438633336306430343733663539666631386532313836623166356332626664
|
||||
39653762353265643861633237326662383466373539633732323833376238383963393837636466
|
||||
66656631666131623166393731643537393161303636353932653062363137376334356238643064
|
||||
34303666656638396263336639636135393536623037666137653132633264316431656438386432
|
||||
34333632616265343435306365373039653036353337633563393739653632656163316636363336
|
||||
32346638393364353634386231616639386164326531353134366639653837653236333030666139
|
||||
64656334336231636337656233383834343763393738643362626665333362353335656131653165
|
||||
35376330336433383262653039643131313437643265343663626363373439643932643063646439
|
||||
37663630363839643263373630646430386536346132383564396463376361343661346661333636
|
||||
39643961643031626462363537633263393838363262626439313838313039373035373634633462
|
||||
38363938343932626131343966616638323632303636383034383536616164393539343635666166
|
||||
39383434313863356434383961383139623436636230323866396366326665623863336438623335
|
||||
33346634303639643131333933363838666336306438646335343931366437326462376438663837
|
||||
34353938343837663930356464373332356530643231653166616331376335643832316365303164
|
||||
32393062313638393936393863613731363233376537323834623164613231393133353635623866
|
||||
35626337336562653265613730363961633662653331663966333430343462666535306133663835
|
||||
64663539303765366331613666653632313233626231313264346332323266653230323332373836
|
||||
33303564633464333064613431383230383535633362373839323334353162623433646230393838
|
||||
33306162613739393338373361616634396636313765326465393332396537613263383339626666
|
||||
63613162616363363138323965373966353366323463313934356530663931653565656164346363
|
||||
37633862366436623030303233396639393434336438623433383530393836626164353064366432
|
||||
35303532393437316162346366346636633135383938323631316563323935383561326335323438
|
||||
30613266643232656138663431666162663330643133643263343237663565323231316239633037
|
||||
39323732386236396136633539383335646634306139643533666636633131623566333137376236
|
||||
39616134306463613864353135313636343365643437323465643862303137663937376233306261
|
||||
31383862356535646563383438396363323838613237623034656561396163376433663262366137
|
||||
63323562346633303162666530616534386539383238366139376263326265343138373139393432
|
||||
35643335363139373139666230626363386232316536306431653964376333366235303763336135
|
||||
65623231336638643034373932376263636336653561646664366138643031316438316465353363
|
||||
38386539363631393433313664323135646562313537376236653635303263633230383866653039
|
||||
66636534336234363438363139366531653237323137613961383831376665626365393462363834
|
||||
36333965366463636233643433616431376436323535396238363933326363333661326462353161
|
||||
66626435373938633832393662313161663336613862343332643766333633653866316464653735
|
||||
31356135363662633961386264613836323435323836386635336338353663333137336666323531
|
||||
36663731336664633763633634613136663866363530613264356431326539316530326161313362
|
||||
62616539356537353261343464356334636134396664353463623163313765633432653932346136
|
||||
32326239373333643461333733646264353238356134613037663836643131316664653539643839
|
||||
30613235623933356565336630323939633266613164306262386666363137666661666131613962
|
||||
61623930663536646462343264336535353634373833316537613839396566376466653736333830
|
||||
33376663613063326230346439626237373232656665633832373364653931663361666432303166
|
||||
663564323132383864336332363139393534
|
||||
36
group_vars/all/vars.yml
Normal file
36
group_vars/all/vars.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Essential
|
||||
#
|
||||
|
||||
root: root
|
||||
user: tudattr
|
||||
timezone: Europe/Berlin
|
||||
puid: "1000"
|
||||
pgid: "1000"
|
||||
pk_path: "/media/veracrypt1/genesis"
|
||||
pubkey: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKqc9fnzfCz8fQDFzla+D8PBhvaMmFu2aF+TYkkZRxl9 tuan@genesis-2022-01-20"
|
||||
|
||||
public_domain: tudattr.dev
|
||||
internal_domain: seyshiro.de
|
||||
|
||||
#
|
||||
# Packages
|
||||
#
|
||||
|
||||
common_packages:
|
||||
- build-essential
|
||||
- curl
|
||||
- git
|
||||
- iperf3
|
||||
- neovim
|
||||
- rsync
|
||||
- smartmontools
|
||||
- sudo
|
||||
- systemd-timesyncd
|
||||
- tree
|
||||
- screen
|
||||
- bat
|
||||
- fd-find
|
||||
- ripgrep
|
||||
|
||||
arch: "{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}"
|
||||
532
group_vars/docker/vars.yml
Normal file
532
group_vars/docker/vars.yml
Normal file
@@ -0,0 +1,532 @@
|
||||
docker:
|
||||
url: "https://download.docker.com/linux"
|
||||
apt_release_channel: "stable"
|
||||
directories:
|
||||
config: "/opt/docker/config/"
|
||||
compose: "/opt/docker/compose/"
|
||||
media: "/media/docker/data/"
|
||||
|
||||
caddy:
|
||||
admin_email: me+acme@tudattr.dev
|
||||
|
||||
domain: "seyshiro.de"
|
||||
|
||||
elk_version: 8.17.0
|
||||
|
||||
services:
|
||||
- name: syncthing
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: syncthing
|
||||
image: syncthing/syncthing
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Data"
|
||||
internal: /var/syncthing/
|
||||
external: /media/docker/data/syncthing/
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 8384
|
||||
external: 8384
|
||||
- name: ""
|
||||
internal: 22000
|
||||
external: 22000
|
||||
- name: ""
|
||||
internal: 22000
|
||||
external: 22000
|
||||
- name: ""
|
||||
internal: 21027
|
||||
external: 21027
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- name: status
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: kuma
|
||||
image: louislam/uptime-kuma:1
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Data"
|
||||
internal: /app/data
|
||||
external: /opt/local/kuma/
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 3001
|
||||
external: 3001
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- name: plex
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: plex
|
||||
image: lscr.io/linuxserver/plex:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config
|
||||
external: /opt/local/plex/config/
|
||||
- name: "TV Series"
|
||||
internal: /tv:ro
|
||||
external: /media/series
|
||||
- name: "Movies"
|
||||
internal: /movies:ro
|
||||
external: /media/movies
|
||||
- name: "Music"
|
||||
internal: /music:ro
|
||||
external: /media/songs
|
||||
devices:
|
||||
- name: "Graphics Card"
|
||||
internal: /dev/dri
|
||||
external: /dev/dri
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 32400
|
||||
external: 32400
|
||||
- name: ""
|
||||
internal: 1900
|
||||
external: 1900
|
||||
- name: ""
|
||||
internal: 3005
|
||||
external: 3005
|
||||
- name: ""
|
||||
internal: 5353
|
||||
external: 5353
|
||||
- name: ""
|
||||
internal: 32410
|
||||
external: 32410
|
||||
- name: ""
|
||||
internal: 8324
|
||||
external: 8324
|
||||
- name: ""
|
||||
internal: 32412
|
||||
external: 32412
|
||||
- name: ""
|
||||
internal: 32469
|
||||
external: 32469
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- VERSION=docker
|
||||
- name: jellyfin
|
||||
vm:
|
||||
- docker-host02
|
||||
container_name: jellyfin
|
||||
image: jellyfin/jellyfin
|
||||
restart: "unless-stopped"
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config
|
||||
external: /opt/local/jellyfin/config
|
||||
- name: "Cache"
|
||||
internal: /cache
|
||||
external: "{{ docker.directories.config }}/jellyfin/cache"
|
||||
- name: "Tv Series"
|
||||
internal: /tv:ro
|
||||
external: /media/series
|
||||
- name: "Music"
|
||||
internal: /movies:ro
|
||||
external: /media/movies
|
||||
- name: "Music"
|
||||
internal: /music:ro
|
||||
external: /media/songs
|
||||
devices:
|
||||
- name: "Graphics Card"
|
||||
internal: /dev/dri
|
||||
external: /dev/dri
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 8096
|
||||
external: 8096
|
||||
environment:
|
||||
- name: hass
|
||||
vm:
|
||||
- docker-host02
|
||||
container_name: homeassistant
|
||||
image: "ghcr.io/home-assistant/home-assistant:stable"
|
||||
restart: unless-stopped
|
||||
privileged: true
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config/
|
||||
external: /opt/local/home-assistant/config/
|
||||
- name: "Local Time"
|
||||
internal: /etc/localtime:ro
|
||||
external: /etc/localtime
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 8123
|
||||
external: 8123
|
||||
- name: ""
|
||||
internal: 4357
|
||||
external: 4357
|
||||
- name: ""
|
||||
internal: 5683
|
||||
external: 5683
|
||||
- name: ""
|
||||
internal: 5683
|
||||
external: 5683
|
||||
- name: ddns
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: ddns-updater
|
||||
image: ghcr.io/qdm12/ddns-updater
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /updater/data/"
|
||||
external: "{{ docker.directories.config }}/ddns-updater/data/"
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 8000
|
||||
external: 8001
|
||||
- name: sonarr
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: sonarr
|
||||
image: lscr.io/linuxserver/sonarr:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config
|
||||
external: /opt/local/sonarr/config
|
||||
- name: "Tv Series"
|
||||
internal: /tv
|
||||
external: /media/series
|
||||
- name: "Torrent Downloads"
|
||||
internal: /downloads
|
||||
external: /media/docker/data/arr_downloads/sonarr
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 8989
|
||||
external: 8989
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- name: radarr
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: radarr
|
||||
image: lscr.io/linuxserver/radarr:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config
|
||||
external: /opt/local/radarr/config
|
||||
- name: "Movies"
|
||||
internal: /movies
|
||||
external: /media/movies
|
||||
- name: "Torrent Downloads"
|
||||
internal: /downloads
|
||||
external: /media/docker/data/arr_downloads/radarr
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 7878
|
||||
external: 7878
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- name: lidarr
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: lidarr
|
||||
image: lscr.io/linuxserver/lidarr:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config
|
||||
external: /opt/local/lidarr/config
|
||||
- name: "Music"
|
||||
internal: /music
|
||||
external: /media/songs
|
||||
- name: "Torrent Downloads"
|
||||
internal: /downloads
|
||||
external: /media/docker/data/arr_downloads/lidarr
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 8686
|
||||
external: 8686
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- name: prowlarr
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: prowlarr
|
||||
image: lscr.io/linuxserver/prowlarr:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config
|
||||
external: /opt/local/prowlarr/config
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 9696
|
||||
external: 9696
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- name: paperless
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: paperless
|
||||
image: ghcr.io/paperless-ngx/paperless-ngx:latest
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- paperless-postgres
|
||||
- paperless-broker
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /usr/src/paperless/data
|
||||
external: /opt/local/paperless/data/data
|
||||
- name: "Media"
|
||||
internal: /usr/src/paperless/media
|
||||
external: /opt/local/paperless/data/media
|
||||
- name: "Document Export"
|
||||
internal: /usr/src/paperless/export
|
||||
external: /opt/local/paperless/data/export
|
||||
- name: "Document Consume"
|
||||
internal: /usr/src/paperless/consume
|
||||
external: /opt/local/paperless/data/consume
|
||||
environment:
|
||||
- "PAPERLESS_REDIS=redis://paperless-broker:6379"
|
||||
- "PAPERLESS_DBHOST=paperless-postgres"
|
||||
- "PAPERLESS_DBUSER=paperless"
|
||||
- "PAPERLESS_DBPASS={{ vault.docker.paperless.dbpass }}"
|
||||
- "USERMAP_UID=1000"
|
||||
- "USERMAP_GID=1000"
|
||||
- "PAPERLESS_URL=https://paperless.{{ domain }}"
|
||||
- "PAPERLESS_TIME_ZONE=Europe/Berlin"
|
||||
- "PAPERLESS_OCR_LANGUAGE=deu"
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 8000
|
||||
external: 8000
|
||||
- name: pdf
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: stirling
|
||||
image: frooodle/s-pdf:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 8080
|
||||
external: 8080
|
||||
- name: git
|
||||
vm:
|
||||
- docker-host02
|
||||
container_name: gitea
|
||||
image: gitea/gitea:1.23.1-rootless
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /etc/gitea
|
||||
external: /opt/local/gitea/config
|
||||
- name: "Data"
|
||||
internal: /var/lib/gitea
|
||||
external: /opt/local/gitea/data
|
||||
- name: "Time Zone"
|
||||
internal: /etc/timezone:ro
|
||||
external: /etc/timezone
|
||||
- name: "Local Time"
|
||||
internal: /etc/localtime:ro
|
||||
external: /etc/localtime
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 3000
|
||||
external: 3000
|
||||
- name: "ssh"
|
||||
internal: 2222
|
||||
external: 2222
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- name: changedetection
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: changedetection
|
||||
image: dgtlmoon/changedetection.io
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- name: "Data"
|
||||
internal: /datastore
|
||||
external: "{{ docker.directories.config }}/changedetection/data/"
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 5000
|
||||
external: 5000
|
||||
- name: gluetun
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: gluetun
|
||||
image: qmcgaw/gluetun
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
- name: "Tunnel"
|
||||
internal: /dev/net/tun
|
||||
external: /dev/net/tun
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /gluetun
|
||||
external: "{{ docker.directories.config }}/gluetun/config"
|
||||
ports:
|
||||
- name: "Qbit Client"
|
||||
internal: 8082
|
||||
external: 8082
|
||||
- name: "Torrentleech Client"
|
||||
internal: 8083
|
||||
external: 8083
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- VPN_SERVICE_PROVIDER=protonvpn
|
||||
- UPDATER_VPN_SERVICE_PROVIDERS=protonvpn
|
||||
- UPDATER_PERIOD=24h
|
||||
- "SERVER_COUNTRIES={{ vault.docker.proton.country }}"
|
||||
- "OPENVPN_USER={{ vault.docker.proton.openvpn_user }}"
|
||||
- "OPENVPN_PASSWORD={{ vault.docker.proton.openvpn_password }}"
|
||||
- name: torrentleech
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: torrentleech
|
||||
image: qbittorrentofficial/qbittorrent-nox
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- gluetun
|
||||
network_mode: "container:gluetun"
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config
|
||||
external: "{{ docker.directories.config }}/torrentleech/config"
|
||||
- name: "Downloads"
|
||||
internal: /downloads
|
||||
external: /media/docker/data/arr_downloads
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: proxy_only
|
||||
external: 8083
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- QBT_EULA="accept"
|
||||
- QBT_WEBUI_PORT="8083"
|
||||
- name: qbit
|
||||
vm:
|
||||
- docker-host00
|
||||
container_name: qbit
|
||||
image: qbittorrentofficial/qbittorrent-nox
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- gluetun
|
||||
network_mode: "container:gluetun"
|
||||
volumes:
|
||||
- name: "Configuration"
|
||||
internal: /config
|
||||
external: "{{ docker.directories.config }}/qbit/config"
|
||||
- name: "Downloads"
|
||||
internal: /downloads
|
||||
external: /media/docker/data/arr_downloads
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: proxy_only
|
||||
external: 8082
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- QBT_EULA="accept"
|
||||
- QBT_WEBUI_PORT="8082"
|
||||
- name: cadvisor
|
||||
vm:
|
||||
- docker-host00
|
||||
- docker-host01
|
||||
- docker-host02
|
||||
container_name: cadvisor
|
||||
image: gcr.io/cadvisor/cadvisor:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- name: ""
|
||||
internal: 8080
|
||||
external: 8081
|
||||
volumes:
|
||||
- name: "Root"
|
||||
internal: /rootfs:ro
|
||||
external: /
|
||||
- name: "Run"
|
||||
internal: /var/run:rw
|
||||
external: /var/run
|
||||
- name: "System"
|
||||
internal: /sys:ro
|
||||
external: /sys
|
||||
- name: "Docker"
|
||||
internal: /var/lib/docker:ro
|
||||
external: /var/lib/docker
|
||||
- name: elasticsearch
|
||||
vm:
|
||||
- docker-host01
|
||||
container_name: elasticsearch
|
||||
image: "docker.elastic.co/elasticsearch/elasticsearch:{{ elk_version }}"
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- name: ""
|
||||
internal: 9200
|
||||
external: 9200
|
||||
- name: ""
|
||||
internal: 9300
|
||||
external: 9300
|
||||
volumes:
|
||||
- name: "data"
|
||||
internal: /usr/share/elasticsearch/data
|
||||
external: "{{ docker.directories.config }}/elk/elasticsearch/data"
|
||||
- name: "certs"
|
||||
internal: /usr/share/elasticsearch/config/certs
|
||||
external: "{{ docker.directories.config }}/elk/certs"
|
||||
environment:
|
||||
- node.name=elasticsearch
|
||||
- cluster.name=docker-cluster
|
||||
- discovery.type=single-node
|
||||
- "ELASTIC_PASSWORD={{ vault.docker.elk.elastic.password }}"
|
||||
- xpack.security.enabled=true
|
||||
- xpack.security.authc.api_key.enabled=true
|
||||
- xpack.security.http.ssl.enabled=true
|
||||
- xpack.security.http.ssl.key=certs/elasticsearch.key
|
||||
- xpack.security.http.ssl.certificate=certs/elasticsearch.crt
|
||||
- xpack.security.http.ssl.certificate_authorities=certs/ca.crt
|
||||
- xpack.security.transport.ssl.enabled=true
|
||||
- xpack.security.transport.ssl.verification_mode=certificate
|
||||
- xpack.security.transport.ssl.key=certs/elasticsearch.key
|
||||
- xpack.security.transport.ssl.certificate=certs/elasticsearch.crt
|
||||
- xpack.security.transport.ssl.certificate_authorities=certs/ca.crt
|
||||
- name: kibana
|
||||
vm:
|
||||
- docker-host01
|
||||
container_name: kibana
|
||||
image: "docker.elastic.co/kibana/kibana:{{ elk_version }}"
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- name: "http"
|
||||
internal: 5601
|
||||
external: 5601
|
||||
volumes:
|
||||
- name: "certs"
|
||||
internal: /usr/share/kibana/config/certs
|
||||
external: "{{ docker.directories.config }}/elk/certs/"
|
||||
environment:
|
||||
- ELASTICSEARCH_HOSTS=["https://elasticsearch:9200"]
|
||||
- ELASTICSEARCH_USERNAME=kibana_system
|
||||
- ELASTICSEARCH_PASSWORD={{ vault.docker.elk.elastic.password }}
|
||||
- SERVER_SSL_ENABLED=true
|
||||
- SERVER_SSL_CERTIFICATE=/usr/share/kibana/config/certs/kibana.crt
|
||||
- SERVER_SSL_KEY=/usr/share/kibana/config/certs/kibana.key
|
||||
28
group_vars/k3s/vars.yml
Normal file
28
group_vars/k3s/vars.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
db:
|
||||
default_user:
|
||||
user: "postgres"
|
||||
name: "k3s"
|
||||
user: "k3s"
|
||||
password: "{{ vault.k3s.postgres.db.password }}"
|
||||
listen_address: "{{ k3s.db.ip }}"
|
||||
|
||||
k3s:
|
||||
net: "192.168.20.0/24"
|
||||
server:
|
||||
ips:
|
||||
- 192.168.20.21
|
||||
- 192.168.20.24
|
||||
- 192.168.20.30
|
||||
loadbalancer:
|
||||
ip: 192.168.20.22
|
||||
default_port: 6443
|
||||
db:
|
||||
ip: 192.168.20.23
|
||||
default_port: "5432"
|
||||
agent:
|
||||
ips:
|
||||
- 192.168.20.25
|
||||
- 192.168.20.26
|
||||
- 192.168.20.27
|
||||
|
||||
k3s_db_connection_string: "postgres://{{ db.user }}:{{ db.password }}@{{ k3s.db.ip }}:{{ k3s.db.default_port }}/{{ db.name }}"
|
||||
10
host_vars/aya01.yml
Normal file
10
host_vars/aya01.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "root"
|
||||
ansible_host: 192.168.20.12
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.pve.aya01.root.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "aya01"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/docker-host00.yml
Normal file
10
host_vars/docker-host00.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.34
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.docker.host00.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "docker-host00"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/docker-host01.yml
Normal file
10
host_vars/docker-host01.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.35
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.docker.host01.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "docker-host01"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/docker-host02.yml
Normal file
10
host_vars/docker-host02.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.36
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.docker.host02.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "docker-host02"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/docker-lb.yml
Normal file
10
host_vars/docker-lb.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.37
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.docker.lb.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "docker-lb"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/inko.yml
Normal file
10
host_vars/inko.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "root"
|
||||
ansible_host: 192.168.20.14
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.pve.inko.root.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "inko"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/k3s-agent00.yml
Normal file
10
host_vars/k3s-agent00.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.25
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.agent00.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "k3s-agent00"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/k3s-agent01.yml
Normal file
10
host_vars/k3s-agent01.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.26
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.agent01.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "k3s-agent01"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/k3s-agent02.yml
Normal file
10
host_vars/k3s-agent02.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.27
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.agent02.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "k3s-agent02"
|
||||
ip: "{{ ansible_host }}"
|
||||
9
host_vars/k3s-loadbalancer.yml
Normal file
9
host_vars/k3s-loadbalancer.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.22
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.loadbalancer.sudo }}"
|
||||
host:
|
||||
hostname: "k3s-loadbalancer"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/k3s-longhorn00.yml
Normal file
10
host_vars/k3s-longhorn00.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.32
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.longhorn00.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "k3s-longhorn00"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/k3s-longhorn01.yml
Normal file
10
host_vars/k3s-longhorn01.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.33
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.longhorn01.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "k3s-longhorn01"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/k3s-longhorn02.yml
Normal file
10
host_vars/k3s-longhorn02.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.31
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.longhorn02.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "k3s-longhorn02"
|
||||
ip: "{{ ansible_host }}"
|
||||
9
host_vars/k3s-postgres.yml
Normal file
9
host_vars/k3s-postgres.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.23
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.postgres.sudo }}"
|
||||
host:
|
||||
hostname: "k3s-postgres"
|
||||
ip: "{{ ansible_host }}"
|
||||
9
host_vars/k3s-server00.yml
Normal file
9
host_vars/k3s-server00.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.21
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.server00.sudo }}"
|
||||
host:
|
||||
hostname: "k3s-server00"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/k3s-server01.yml
Normal file
10
host_vars/k3s-server01.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.24
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.server01.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "k3s-server01"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/k3s-server02.yml
Normal file
10
host_vars/k3s-server02.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "{{ user }}"
|
||||
ansible_host: 192.168.20.30
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.k3s.server02.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "k3s-server02"
|
||||
ip: "{{ ansible_host }}"
|
||||
10
host_vars/lulu.yml
Normal file
10
host_vars/lulu.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
ansible_user: "root"
|
||||
ansible_host: 192.168.20.28
|
||||
ansible_port: 22
|
||||
ansible_ssh_private_key_file: "{{ pk_path }}"
|
||||
ansible_become_pass: "{{ vault.pve.lulu.root.sudo }}"
|
||||
|
||||
host:
|
||||
hostname: "lulu"
|
||||
ip: "{{ ansible_host }}"
|
||||
58
inventory/production
Normal file
58
inventory/production
Normal file
@@ -0,0 +1,58 @@
|
||||
[proxmox]
|
||||
aya01
|
||||
lulu
|
||||
inko
|
||||
|
||||
[k3s]
|
||||
k3s-postgres
|
||||
k3s-loadbalancer
|
||||
k3s-server[00:02]
|
||||
k3s-agent[00:02]
|
||||
k3s-longhorn[00:02]
|
||||
|
||||
[vm]
|
||||
k3s-postgres
|
||||
k3s-loadbalancer
|
||||
k3s-agent[00:02]
|
||||
k3s-server[00:02]
|
||||
k3s-longhorn[00:02]
|
||||
docker-host[00:02]
|
||||
|
||||
[k3s_nodes]
|
||||
k3s-server[00:02]
|
||||
k3s-agent[00:02]
|
||||
k3s-longhorn[00:02]
|
||||
|
||||
[docker]
|
||||
docker-host[00:02]
|
||||
docker-lb
|
||||
|
||||
[vps]
|
||||
mii
|
||||
|
||||
[k3s_server]
|
||||
k3s-server[00:02]
|
||||
|
||||
[k3s_agent]
|
||||
k3s-agent[00:02]
|
||||
|
||||
[k3s_storage]
|
||||
k3s-longhorn[00:02]
|
||||
|
||||
[db]
|
||||
k3s-postgres
|
||||
|
||||
[loadbalancer]
|
||||
k3s-loadbalancer
|
||||
|
||||
[docker_host]
|
||||
docker-host[00:02]
|
||||
|
||||
[docker_lb]
|
||||
docker-lb
|
||||
|
||||
[local]
|
||||
localhost ansible_connection=local
|
||||
|
||||
[vm:vars]
|
||||
ansible_ssh_common_args='-o ProxyCommand="ssh -p 22 -W %h:%p -q aya01"'
|
||||
2
inventory/test
Normal file
2
inventory/test
Normal file
@@ -0,0 +1,2 @@
|
||||
[local]
|
||||
test ansible_connection=local ansible_become_pass=vagrant
|
||||
10
playbooks/common-k3s.yml
Normal file
10
playbooks/common-k3s.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Run the common role on k3s
|
||||
hosts: k3s
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
roles:
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
19
playbooks/db.yml
Normal file
19
playbooks/db.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
- name: Set up Servers
|
||||
hosts: db
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
roles:
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
- role: postgres
|
||||
tags:
|
||||
- postgres
|
||||
- role: node_exporter
|
||||
tags:
|
||||
- node_exporter
|
||||
- role: postgres_exporter
|
||||
tags:
|
||||
- postgres_exporter
|
||||
@@ -1,11 +1,13 @@
|
||||
---
|
||||
- name: Set up Servers
|
||||
hosts: docker_host
|
||||
gather_facts: true
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
roles:
|
||||
# - role: common
|
||||
# tags:
|
||||
# - common
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
- role: docker_host
|
||||
tags:
|
||||
- docker_host
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
- name: Set up reverse proxy for docker
|
||||
hosts: docker
|
||||
gather_facts: true
|
||||
hosts: docker_lb
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
roles:
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
when: inventory_hostname in groups["docker_lb"]
|
||||
- role: reverse_proxy
|
||||
tags:
|
||||
- reverse_proxy
|
||||
when: inventory_hostname in groups["docker_lb"]
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
- name: Setup Docker Hosts
|
||||
ansible.builtin.import_playbook: docker-host.yaml
|
||||
- name: Setup Docker load balancer
|
||||
ansible.builtin.import_playbook: docker-lb.yaml
|
||||
@@ -1,16 +0,0 @@
|
||||
- name: Set up Agents
|
||||
hosts: k3s
|
||||
gather_facts: true
|
||||
roles:
|
||||
- role: common
|
||||
when: inventory_hostname in groups["k3s_agent"]
|
||||
tags:
|
||||
- common
|
||||
- role: k3s_agent
|
||||
when: inventory_hostname in groups["k3s_agent"]
|
||||
tags:
|
||||
- k3s_agent
|
||||
# - role: node_exporter
|
||||
# when: inventory_hostname in groups["k3s_agent"]
|
||||
# tags:
|
||||
# - node_exporter
|
||||
31
playbooks/k3s-agents.yml
Normal file
31
playbooks/k3s-agents.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
- name: Set up Agents
|
||||
hosts: k3s_nodes
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
pre_tasks:
|
||||
- name: Get K3s token from the first server
|
||||
when: host.ip == k3s.server.ips[0] and inventory_hostname in groups["k3s_server"]
|
||||
slurp:
|
||||
src: /var/lib/rancher/k3s/server/node-token
|
||||
register: k3s_token
|
||||
become: true
|
||||
|
||||
- name: Set fact on k3s.server.ips[0]
|
||||
when: host.ip == k3s.server.ips[0] and inventory_hostname in groups["k3s_server"]
|
||||
set_fact: k3s_token="{{ k3s_token['content'] | b64decode | trim }}"
|
||||
|
||||
roles:
|
||||
- role: common
|
||||
when: inventory_hostname in groups["k3s_agent"]
|
||||
tags:
|
||||
- common
|
||||
- role: k3s_agent
|
||||
when: inventory_hostname in groups["k3s_agent"]
|
||||
k3s_token: "{{ hostvars[(hostvars | dict2items | map(attribute='value') | map('dict2items') | map('selectattr', 'key', 'match', 'host') | map('selectattr', 'value.ip', 'match', k3s.server.ips[0] ) | select() | first | items2dict).host.hostname].k3s_token }}"
|
||||
tags:
|
||||
- k3s_agent
|
||||
- role: node_exporter
|
||||
when: inventory_hostname in groups["k3s_agent"]
|
||||
tags:
|
||||
- node_exporter
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
- name: Set up Servers
|
||||
hosts: k3s
|
||||
gather_facts: true
|
||||
roles:
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
when: inventory_hostname in groups["k3s_loadbalancer"]
|
||||
- role: k3s_loadbalancer
|
||||
tags:
|
||||
- k3s_loadbalancer
|
||||
when: inventory_hostname in groups["k3s_loadbalancer"]
|
||||
# - role: node_exporter
|
||||
# tags:
|
||||
# - node_exporter
|
||||
# when: inventory_hostname in groups["k3s_loadbalancer"]
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
- name: Set up Servers
|
||||
hosts: k3s
|
||||
gather_facts: true
|
||||
roles:
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
when: inventory_hostname in groups["k3s_server"]
|
||||
- role: k3s_server
|
||||
tags:
|
||||
- k3s_server
|
||||
when: inventory_hostname in groups["k3s_server"]
|
||||
# - role: node_exporter
|
||||
# tags:
|
||||
# - node_exporter
|
||||
# when: inventory_hostname in groups["k3s_server"]
|
||||
16
playbooks/k3s-servers.yml
Normal file
16
playbooks/k3s-servers.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Set up Servers
|
||||
hosts: k3s_server
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
roles:
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
- role: k3s_server
|
||||
tags:
|
||||
- k3s_server
|
||||
- role: node_exporter
|
||||
tags:
|
||||
- node_exporter
|
||||
@@ -1,16 +0,0 @@
|
||||
- name: Set up storage
|
||||
hosts: k3s_nodes
|
||||
gather_facts: true
|
||||
roles:
|
||||
- role: common
|
||||
when: inventory_hostname in groups["k3s_storage"]
|
||||
tags:
|
||||
- common
|
||||
- role: k3s_storage
|
||||
when: inventory_hostname in groups["k3s_storage"]
|
||||
tags:
|
||||
- k3s_storage
|
||||
# - role: node_exporter
|
||||
# when: inventory_hostname in groups["k3s_storage"]
|
||||
# tags:
|
||||
# - node_exporter
|
||||
31
playbooks/k3s-storage.yml
Normal file
31
playbooks/k3s-storage.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
- name: Set up storage
|
||||
hosts: k3s_nodes
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
pre_tasks:
|
||||
- name: Get K3s token from the first server
|
||||
when: host.ip == k3s.server.ips[0] and inventory_hostname in groups["k3s_server"]
|
||||
slurp:
|
||||
src: /var/lib/rancher/k3s/server/node-token
|
||||
register: k3s_token
|
||||
become: true
|
||||
|
||||
- name: Set fact on k3s.server.ips[0]
|
||||
when: host.ip == k3s.server.ips[0] and inventory_hostname in groups["k3s_server"]
|
||||
set_fact: k3s_token="{{ k3s_token['content'] | b64decode | trim }}"
|
||||
|
||||
roles:
|
||||
- role: common
|
||||
when: inventory_hostname in groups["k3s_storage"]
|
||||
tags:
|
||||
- common
|
||||
- role: k3s_storage
|
||||
when: inventory_hostname in groups["k3s_storage"]
|
||||
k3s_token: "{{ hostvars[(hostvars | dict2items | map(attribute='value') | map('dict2items') | map('selectattr', 'key', 'match', 'host') | map('selectattr', 'value.ip', 'match', k3s.server.ips[0] ) | select() | first | items2dict).host.hostname].k3s_token }}"
|
||||
tags:
|
||||
- k3s_storage
|
||||
- role: node_exporter
|
||||
when: inventory_hostname in groups["k3s_storage"]
|
||||
tags:
|
||||
- node_exporter
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
- name: Setup Kubernetes Cluster
|
||||
hosts: kubernetes
|
||||
any_errors_fatal: true
|
||||
gather_facts: false
|
||||
vars:
|
||||
is_localhost: "{{ inventory_hostname == '127.0.0.1' }}"
|
||||
roles:
|
||||
- role: kubernetes_argocd
|
||||
when: is_localhost
|
||||
16
playbooks/loadbalancer.yml
Normal file
16
playbooks/loadbalancer.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Set up Servers
|
||||
hosts: loadbalancer
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
roles:
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
- role: loadbalancer
|
||||
tags:
|
||||
- loadbalancer
|
||||
- role: node_exporter
|
||||
tags:
|
||||
- node_exporter
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
- name: Create new VM(s)
|
||||
ansible.builtin.import_playbook: proxmox.yaml
|
||||
|
||||
- name: Provision VM
|
||||
ansible.builtin.import_playbook: k3s-agents.yaml
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
- name: Run proxmox vm playbook
|
||||
hosts: proxmox
|
||||
gather_facts: true
|
||||
vars:
|
||||
is_localhost: "{{ inventory_hostname == '127.0.0.1' }}"
|
||||
is_proxmox_node: "{{ 'proxmox_nodes' in group_names }}"
|
||||
roles:
|
||||
- role: common
|
||||
tags:
|
||||
- common
|
||||
when: not is_localhost
|
||||
- role: proxmox
|
||||
tags:
|
||||
- proxmox
|
||||
9
playbooks/test.yml
Normal file
9
playbooks/test.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- hosts: db
|
||||
gather_facts: yes
|
||||
vars_files:
|
||||
- secrets.yml
|
||||
tasks:
|
||||
- name: Print the database connection string
|
||||
debug:
|
||||
msg: "{{ k3s_db_connection_string }}"
|
||||
5
playbooks/ubuntu.yml
Normal file
5
playbooks/ubuntu.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
- name: Provision Local Ubuntu Machine
|
||||
hosts: local
|
||||
gather_facts: true
|
||||
roles:
|
||||
- ubuntu
|
||||
@@ -1,28 +0,0 @@
|
||||
cachetools==5.5.2
|
||||
certifi==2025.1.31
|
||||
cfgv==3.4.0
|
||||
charset-normalizer==3.4.1
|
||||
distlib==0.4.0
|
||||
durationpy==0.10
|
||||
filelock==3.18.0
|
||||
google-auth==2.40.3
|
||||
identify==2.6.12
|
||||
idna==3.10
|
||||
kubernetes==33.1.0
|
||||
nc-dnsapi==0.1.3
|
||||
nodeenv==1.9.1
|
||||
oauthlib==3.3.1
|
||||
platformdirs==4.3.8
|
||||
pre_commit==4.2.0
|
||||
proxmoxer==2.2.0
|
||||
pyasn1==0.6.1
|
||||
pyasn1_modules==0.4.2
|
||||
python-dateutil==2.9.0.post0
|
||||
PyYAML==6.0.2
|
||||
requests==2.32.3
|
||||
requests-oauthlib==2.0.0
|
||||
rsa==4.9.1
|
||||
six==1.17.0
|
||||
urllib3==2.3.0
|
||||
virtualenv==20.32.0
|
||||
websocket-client==1.8.0
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
collections:
|
||||
- name: community.docker
|
||||
- name: community.general
|
||||
- name: kubernetes.core
|
||||
@@ -1,72 +0,0 @@
|
||||
# Ansible Role: common
|
||||
|
||||
This role configures a baseline set of common configurations for Debian-based systems, including time synchronization, essential packages, hostname, and specific developer tools.
|
||||
|
||||
## Requirements
|
||||
|
||||
None.
|
||||
|
||||
## Role Variables
|
||||
|
||||
Available variables are listed below, along with default values (see `vars/main.yml`):
|
||||
|
||||
```yaml
|
||||
# A list of common packages to install via apt.
|
||||
common_packages:
|
||||
- build-essential
|
||||
- curl
|
||||
- git
|
||||
- iperf3
|
||||
- neovim
|
||||
- rsync
|
||||
- smartmontools
|
||||
- sudo
|
||||
- systemd-timesyncd
|
||||
- tree
|
||||
- screen
|
||||
- bat
|
||||
- fd-find
|
||||
- ripgrep
|
||||
- nfs-common
|
||||
- open-iscsi
|
||||
- parted
|
||||
|
||||
# The hostname to configure.
|
||||
hostname: "new-host"
|
||||
```
|
||||
|
||||
## Tasks
|
||||
|
||||
The role performs the following tasks:
|
||||
|
||||
1. **Configure Time**: Sets up `systemd-timesyncd` and timezone.
|
||||
2. **Configure Packages**: Installs the list of `common_packages`.
|
||||
3. **Configure Hostname**: Sets the system hostname.
|
||||
4. **Configure Extra-Packages**:
|
||||
- Installs `eza` (modern ls replacement).
|
||||
- Installs `bottom` (process viewer).
|
||||
- Installs `neovim` from AppImage and clones a custom configuration.
|
||||
5. **Configure Bash**: Sets up bash aliases and prompt.
|
||||
6. **Configure SSH**: Configures `sshd_config` for security.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Example Playbook
|
||||
|
||||
```yaml
|
||||
- hosts: servers
|
||||
roles:
|
||||
- role: common
|
||||
vars:
|
||||
hostname: "my-server"
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Author Information
|
||||
|
||||
This role was created in 2025 by [TuDatTr](https://codeberg.org/tudattr/).
|
||||
@@ -1,80 +0,0 @@
|
||||
xterm-ghostty|ghostty|Ghostty,
|
||||
am, bce, ccc, hs, km, mc5i, mir, msgr, npc, xenl, AX, Su, Tc, XT, fullkbd,
|
||||
colors#0x100, cols#80, it#8, lines#24, pairs#0x7fff,
|
||||
acsc=++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
|
||||
bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l,
|
||||
clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=\r,
|
||||
csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
|
||||
cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C,
|
||||
cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A,
|
||||
cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m,
|
||||
dl=\E[%p1%dM, dl1=\E[M, dsl=\E]2;\007, ech=\E[%p1%dX,
|
||||
ed=\E[J, el=\E[K, el1=\E[1K, flash=\E[?5h$<100/>\E[?5l,
|
||||
fsl=^G, home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH,
|
||||
ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=\n,
|
||||
indn=\E[%p1%dS,
|
||||
initc=\E]4;%p1%d;rgb:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
|
||||
invis=\E[8m, kDC=\E[3;2~, kEND=\E[1;2F, kHOM=\E[1;2H,
|
||||
kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~, kPRV=\E[5;2~,
|
||||
kRIT=\E[1;2C, kbs=^?, kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB,
|
||||
kcuf1=\EOC, kcuu1=\EOA, kdch1=\E[3~, kend=\EOF, kent=\EOM,
|
||||
kf1=\EOP, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~,
|
||||
kf13=\E[1;2P, kf14=\E[1;2Q, kf15=\E[1;2R, kf16=\E[1;2S,
|
||||
kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~, kf2=\EOQ,
|
||||
kf20=\E[19;2~, kf21=\E[20;2~, kf22=\E[21;2~,
|
||||
kf23=\E[23;2~, kf24=\E[24;2~, kf25=\E[1;5P, kf26=\E[1;5Q,
|
||||
kf27=\E[1;5R, kf28=\E[1;5S, kf29=\E[15;5~, kf3=\EOR,
|
||||
kf30=\E[17;5~, kf31=\E[18;5~, kf32=\E[19;5~,
|
||||
kf33=\E[20;5~, kf34=\E[21;5~, kf35=\E[23;5~,
|
||||
kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q, kf39=\E[1;6R,
|
||||
kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~, kf42=\E[17;6~,
|
||||
kf43=\E[18;6~, kf44=\E[19;6~, kf45=\E[20;6~,
|
||||
kf46=\E[21;6~, kf47=\E[23;6~, kf48=\E[24;6~,
|
||||
kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q, kf51=\E[1;3R,
|
||||
kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~,
|
||||
kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~,
|
||||
kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~,
|
||||
kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~,
|
||||
kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~,
|
||||
kind=\E[1;2B, kmous=\E[<, knp=\E[6~, kpp=\E[5~,
|
||||
kri=\E[1;2A, oc=\E]104\007, op=\E[39;49m, rc=\E8,
|
||||
rep=%p1%c\E[%p2%{1}%-%db, rev=\E[7m, ri=\EM,
|
||||
rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, rmam=\E[?7l,
|
||||
rmcup=\E[?1049l, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[27m,
|
||||
rmul=\E[24m, rs1=\E]\E\\\Ec, sc=\E7,
|
||||
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
|
||||
setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
|
||||
sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
|
||||
sgr0=\E(B\E[m, sitm=\E[3m, smacs=\E(0, smam=\E[?7h,
|
||||
smcup=\E[?1049h, smir=\E[4h, smkx=\E[?1h\E=, smso=\E[7m,
|
||||
smul=\E[4m, tbc=\E[3g, tsl=\E]2;, u6=\E[%i%d;%dR, u7=\E[6n,
|
||||
u8=\E[?%[;0123456789]c, u9=\E[c, vpa=\E[%i%p1%dd,
|
||||
BD=\E[?2004l, BE=\E[?2004h, Clmg=\E[s,
|
||||
Cmg=\E[%i%p1%d;%p2%ds, Dsmg=\E[?69l, E3=\E[3J,
|
||||
Enmg=\E[?69h, Ms=\E]52;%p1%s;%p2%s\007, PE=\E[201~,
|
||||
PS=\E[200~, RV=\E[>c, Se=\E[2 q,
|
||||
Setulc=\E[58:2::%p1%{65536}%/%d:%p1%{256}%/%{255}%&%d:%p1%{255}%&%d%;m,
|
||||
Smulx=\E[4:%p1%dm, Ss=\E[%p1%d q,
|
||||
Sync=\E[?2026%?%p1%{1}%-%tl%eh%;,
|
||||
XM=\E[?1006;1000%?%p1%{1}%=%th%el%;, XR=\E[>0q,
|
||||
fd=\E[?1004l, fe=\E[?1004h, kDC3=\E[3;3~, kDC4=\E[3;4~,
|
||||
kDC5=\E[3;5~, kDC6=\E[3;6~, kDC7=\E[3;7~, kDN=\E[1;2B,
|
||||
kDN3=\E[1;3B, kDN4=\E[1;4B, kDN5=\E[1;5B, kDN6=\E[1;6B,
|
||||
kDN7=\E[1;7B, kEND3=\E[1;3F, kEND4=\E[1;4F,
|
||||
kEND5=\E[1;5F, kEND6=\E[1;6F, kEND7=\E[1;7F,
|
||||
kHOM3=\E[1;3H, kHOM4=\E[1;4H, kHOM5=\E[1;5H,
|
||||
kHOM6=\E[1;6H, kHOM7=\E[1;7H, kIC3=\E[2;3~, kIC4=\E[2;4~,
|
||||
kIC5=\E[2;5~, kIC6=\E[2;6~, kIC7=\E[2;7~, kLFT3=\E[1;3D,
|
||||
kLFT4=\E[1;4D, kLFT5=\E[1;5D, kLFT6=\E[1;6D,
|
||||
kLFT7=\E[1;7D, kNXT3=\E[6;3~, kNXT4=\E[6;4~,
|
||||
kNXT5=\E[6;5~, kNXT6=\E[6;6~, kNXT7=\E[6;7~,
|
||||
kPRV3=\E[5;3~, kPRV4=\E[5;4~, kPRV5=\E[5;5~,
|
||||
kPRV6=\E[5;6~, kPRV7=\E[5;7~, kRIT3=\E[1;3C,
|
||||
kRIT4=\E[1;4C, kRIT5=\E[1;5C, kRIT6=\E[1;6C,
|
||||
kRIT7=\E[1;7C, kUP=\E[1;2A, kUP3=\E[1;3A, kUP4=\E[1;4A,
|
||||
kUP5=\E[1;5A, kUP6=\E[1;6A, kUP7=\E[1;7A, kxIN=\E[I,
|
||||
kxOUT=\E[O, rmxx=\E[29m, rv=\E\\[[0-9]+;[0-9]+;[0-9]+c,
|
||||
setrgbb=\E[48:2:%p1%d:%p2%d:%p3%dm,
|
||||
setrgbf=\E[38:2:%p1%d:%p2%d:%p3%dm, smxx=\E[9m,
|
||||
xm=\E[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;,
|
||||
xr=\EP>\\|[ -~]+a\E\\,
|
||||
@@ -1,18 +0,0 @@
|
||||
Protocol 2
|
||||
PermitRootLogin yes
|
||||
MaxAuthTries 3
|
||||
PubkeyAuthentication yes
|
||||
PasswordAuthentication no
|
||||
PermitEmptyPasswords no
|
||||
ChallengeResponseAuthentication no
|
||||
UsePAM yes
|
||||
AllowAgentForwarding no
|
||||
AllowTcpForwarding yes
|
||||
X11Forwarding no
|
||||
PrintMotd no
|
||||
TCPKeepAlive no
|
||||
ClientAliveCountMax 2
|
||||
TrustedUserCAKeys /etc/ssh/vault-ca.pub
|
||||
UseDNS yes
|
||||
AcceptEnv LANG LC_*
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
@@ -1 +0,0 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDxIbkko72kVSfYDjJpiMH9SjHUGqBn3MbBvmotsPQhybFgnnkBpX/3fM9olP+Z6PGsmbOEs0fOjPS6uY5hjKcKsyHdZfS6cA4wjY/DL8fwATAW5FCDBtMpdg2/sb8j9jutHHs4sQeRBolVwKcv+ZAaJNnOzNHwxVUfT9bNwShthnAFjkY7oZo657FRomlkDJjmGQuratP0veKA8jYzqqPWwWidTGQerLYTyJ3Z8pbQa5eN7svrvabjjDLbVTDESE8st9WEmwvAwoj7Kz+WovCy0Uz7LRFVmaRiapM8SXtPPUC0xfyzAB3NxwBtxizdUMlShvLcL6cujcUBMulVMpsqEaOESTpmVTrMJhnJPZG/3j9ziGoYIa6hMj1J9/qLQ5dDNVVXMxw99G31x0LJoy12IE90P4Cahux8iN0Cp4oB4+B6/qledxs1fcRzsnQY/ickjKhqcJwgHzsnwjDkeYRaYte5x4f/gJ77kA20nPto7mxr2mhWot/i9B1KlMURVXOH/q4nrzhJ0hPJpM0UtzQ58TmzE4Osf/B5yoe8V//6XnelbmG/nKCIzg12d7PvaLjbFMn8IgOwDMRlip+vpyadRr/+pCawrfo4vLF7BsnJ84aoByIpbwaysgaYHtjfZWImorMVkgviC4O6Hn9/ZiLNze2A9DaNUnLVJ0nYNbmv9Q==
|
||||
@@ -3,4 +3,4 @@
|
||||
service:
|
||||
name: sshd
|
||||
state: restarted
|
||||
become: true
|
||||
become: yes
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
- name: Copy bash-configs
|
||||
ansible.builtin.template:
|
||||
src: "files/bash/{{ item }}"
|
||||
dest: "{{ ansible_env.HOME }}/.{{ item }}"
|
||||
owner: "{{ ansible_user_id }}"
|
||||
group: "{{ ansible_user_id }}"
|
||||
mode: "644"
|
||||
loop:
|
||||
- bashrc
|
||||
- bash_aliases
|
||||
|
||||
- name: Copy ghostty infocmp
|
||||
ansible.builtin.copy:
|
||||
src: files/ghostty/infocmp
|
||||
dest: "{{ ansible_env.HOME }}/ghostty"
|
||||
owner: "{{ ansible_user_id }}"
|
||||
group: "{{ ansible_user_id }}"
|
||||
mode: "0644"
|
||||
register: ghostty_terminfo
|
||||
|
||||
- name: Compile ghostty terminalinfo
|
||||
ansible.builtin.command: "tic -x {{ ansible_env.HOME }}/ghostty"
|
||||
when: ghostty_terminfo.changed
|
||||
12
roles/common/tasks/bash.yml
Normal file
12
roles/common/tasks/bash.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Copy bash-configs
|
||||
ansible.builtin.template:
|
||||
src: "files/bash/{{ item }}"
|
||||
dest: "/home/{{ user }}/.{{ item }}"
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: "644"
|
||||
loop:
|
||||
- bashrc
|
||||
- bash_aliases
|
||||
become: true
|
||||
@@ -11,6 +11,7 @@
|
||||
url: https://raw.githubusercontent.com/eza-community/eza/main/deb.asc
|
||||
dest: /etc/apt/keyrings/gierens.asc
|
||||
mode: "0644"
|
||||
register: gpg_key_result
|
||||
become: true
|
||||
|
||||
- name: Add Gierens repository to apt sources
|
||||
@@ -79,13 +80,12 @@
|
||||
path: ~/.config/nvim
|
||||
register: nvim_config
|
||||
|
||||
- name: Clone personal Neovim config directory
|
||||
- name: Clone LazyVim starter to Neovim config directory
|
||||
ansible.builtin.git:
|
||||
repo: https://codeberg.org/tudattr/nvim
|
||||
repo: https://github.com/LazyVim/starter
|
||||
dest: ~/.config/nvim
|
||||
clone: true
|
||||
update: false
|
||||
version: 1.0.0
|
||||
when: not nvim_config.stat.exists
|
||||
|
||||
- name: Remove .git directory from Neovim config
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
- name: Set a hostname
|
||||
ansible.builtin.hostname:
|
||||
name: "{{ inventory_hostname }}"
|
||||
name: "{{ host.hostname }}"
|
||||
become: true
|
||||
|
||||
- name: Update /etc/hosts to reflect the new hostname
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/hosts
|
||||
regexp: '^127\.0\.1\.1'
|
||||
line: "127.0.1.1 {{ inventory_hostname }}"
|
||||
line: "127.0.1.1 {{ host.hostname }}"
|
||||
state: present
|
||||
backup: true
|
||||
become: true
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
- name: Configure Time
|
||||
ansible.builtin.include_tasks: time.yaml
|
||||
- name: Configure Packages
|
||||
ansible.builtin.include_tasks: packages.yaml
|
||||
- name: Configure Hostname
|
||||
ansible.builtin.include_tasks: hostname.yaml
|
||||
- name: Configure Extra-Packages
|
||||
ansible.builtin.include_tasks: extra_packages.yaml
|
||||
- name: Configure Bash
|
||||
ansible.builtin.include_tasks: bash.yaml
|
||||
- name: Configure SSH
|
||||
ansible.builtin.include_tasks: sshd.yaml
|
||||
13
roles/common/tasks/main.yml
Normal file
13
roles/common/tasks/main.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Configure Time
|
||||
ansible.builtin.include_tasks: time.yml
|
||||
- name: Configure Hostname
|
||||
ansible.builtin.include_tasks: hostname.yml
|
||||
- name: Configure Packages
|
||||
ansible.builtin.include_tasks: packages.yml
|
||||
- name: Configure Extra-Packages
|
||||
ansible.builtin.include_tasks: extra_packages.yml
|
||||
- name: Configure Bash
|
||||
ansible.builtin.include_tasks: bash.yml
|
||||
- name: Configure SSH
|
||||
ansible.builtin.include_tasks: sshd.yml
|
||||
@@ -1,28 +0,0 @@
|
||||
---
|
||||
- name: Update and upgrade packages
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
upgrade: true
|
||||
autoremove: true
|
||||
become: true
|
||||
when: ansible_user_id != "root"
|
||||
|
||||
- name: Install base packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ common_packages }}"
|
||||
state: present
|
||||
become: true
|
||||
when: ansible_user_id != "root"
|
||||
|
||||
- name: Update and upgrade packages
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
upgrade: true
|
||||
autoremove: true
|
||||
when: ansible_user_id == "root"
|
||||
|
||||
- name: Install base packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ common_packages }}"
|
||||
state: present
|
||||
when: ansible_user_id == "root"
|
||||
13
roles/common/tasks/packages.yml
Normal file
13
roles/common/tasks/packages.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Update and upgrade packages
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
upgrade: true
|
||||
autoremove: true
|
||||
become: true
|
||||
|
||||
- name: Install base packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ common_packages }}"
|
||||
state: present
|
||||
become: true
|
||||
@@ -1,28 +0,0 @@
|
||||
---
|
||||
- name: Copy user sshd_config
|
||||
ansible.builtin.template:
|
||||
src: files/ssh/user/sshd_config
|
||||
dest: /etc/ssh/sshd_config
|
||||
mode: "644"
|
||||
backup: true
|
||||
notify:
|
||||
- Restart sshd
|
||||
become: true
|
||||
when: ansible_user_id != "root"
|
||||
|
||||
- name: Copy root sshd_config
|
||||
ansible.builtin.template:
|
||||
src: files/ssh/root/sshd_config
|
||||
dest: /etc/ssh/sshd_config
|
||||
mode: "644"
|
||||
backup: true
|
||||
notify:
|
||||
- Restart sshd
|
||||
when: ansible_user_id == "root"
|
||||
|
||||
- name: Copy pubkey
|
||||
ansible.builtin.copy:
|
||||
src: files/ssh/vault-ca.pub
|
||||
dest: "/etc/ssh/vault-ca.pub"
|
||||
mode: "644"
|
||||
become: true
|
||||
17
roles/common/tasks/sshd.yml
Normal file
17
roles/common/tasks/sshd.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Copy sshd_config
|
||||
ansible.builtin.template:
|
||||
src: templates/ssh/sshd_config
|
||||
dest: /etc/ssh/sshd_config
|
||||
mode: "644"
|
||||
notify:
|
||||
- Restart sshd
|
||||
become: true
|
||||
|
||||
- name: Copy pubkey
|
||||
ansible.builtin.copy:
|
||||
content: "{{ pubkey }}"
|
||||
dest: "/home/{{ user }}/.ssh/authorized_keys"
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: "644"
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
- name: Set timezone
|
||||
community.general.timezone:
|
||||
name: "{{ timezone }}"
|
||||
become: true
|
||||
when: ansible_user_id != "root"
|
||||
|
||||
- name: Set timezone
|
||||
community.general.timezone:
|
||||
name: "{{ timezone }}"
|
||||
when: ansible_user_id == "root"
|
||||
4
roles/common/tasks/time.yml
Normal file
4
roles/common/tasks/time.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
- name: Set timezone to "{{ timezone }}"
|
||||
community.general.timezone:
|
||||
name: "{{ timezone }}"
|
||||
@@ -1,3 +1,4 @@
|
||||
Include /etc/ssh/sshd_config.d/*.conf
|
||||
Protocol 2
|
||||
PermitRootLogin no
|
||||
MaxAuthTries 3
|
||||
@@ -12,7 +13,6 @@ X11Forwarding no
|
||||
PrintMotd no
|
||||
TCPKeepAlive no
|
||||
ClientAliveCountMax 2
|
||||
TrustedUserCAKeys /etc/ssh/vault-ca.pub
|
||||
UseDNS yes
|
||||
AcceptEnv LANG LC_*
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
@@ -1,18 +0,0 @@
|
||||
common_packages:
|
||||
- build-essential
|
||||
- curl
|
||||
- git
|
||||
- iperf3
|
||||
- neovim
|
||||
- rsync
|
||||
- smartmontools
|
||||
- sudo
|
||||
- systemd-timesyncd
|
||||
- tree
|
||||
- screen
|
||||
- bat
|
||||
- fd-find
|
||||
- ripgrep
|
||||
- nfs-common
|
||||
- open-iscsi
|
||||
- parted
|
||||
@@ -1,85 +0,0 @@
|
||||
# Ansible Role: Docker Host
|
||||
|
||||
This role sets up a Docker host, installs Docker, and configures it according to the provided variables. It also handles user and group management, directory setup, and deployment of Docker Compose services.
|
||||
|
||||
## Role Variables
|
||||
|
||||
### General
|
||||
|
||||
- `docker_host_package_common_dependencies`: A list of common packages to be installed on the host.
|
||||
- Default: `nfs-common`
|
||||
- `apt_lock_files`: A list of apt lock files to check.
|
||||
- `arch`: The architecture of the host.
|
||||
- Default: `arm64` if `ansible_architecture` is `aarch64`, otherwise `amd64`.
|
||||
|
||||
### Docker
|
||||
|
||||
- `docker.url`: The URL for the Docker repository.
|
||||
- Default: `https://download.docker.com/linux`
|
||||
- `docker.apt_release_channel`: The Docker apt release channel.
|
||||
- Default: `stable`
|
||||
- `docker.directories.local`: The local directory for Docker data.
|
||||
- Default: `/opt/local`
|
||||
- `docker.directories.config`: The directory for Docker configurations.
|
||||
- Default: `/opt/config`
|
||||
- `docker.directories.compose`: The directory for Docker Compose files.
|
||||
- Default: `/opt/compose`
|
||||
|
||||
### Keycloak
|
||||
|
||||
- `keycloak_config`: A dictionary containing the Keycloak configuration. See `templates/keycloak/realm.json.j2` for more details.
|
||||
|
||||
### Services
|
||||
|
||||
- `services`: A list of dictionaries, where each dictionary represents a Docker Compose service. See `templates/compose.yaml.j2` for more details.
|
||||
|
||||
## Tasks
|
||||
|
||||
The role performs the following tasks:
|
||||
|
||||
1. **Setup VM**:
|
||||
- Includes `non-free` and `non-free-firmware` components in the apt sources.
|
||||
- Installs common packages.
|
||||
- Removes cloud kernel packages.
|
||||
- Reboots the host.
|
||||
2. **Install Docker**:
|
||||
- Uninstalls old Docker versions.
|
||||
- Installs dependencies for using repositories over HTTPS.
|
||||
- Adds the Docker apt key and repository.
|
||||
- Installs Docker Engine, containerd, and Docker Compose.
|
||||
3. **Setup user and group for Docker**:
|
||||
- Ensures the `docker` group exists.
|
||||
- Adds the `ansible_user_id` to the `docker` group.
|
||||
- Reboots the host.
|
||||
4. **Setup directory structure for Docker**:
|
||||
- Creates necessary directories for Docker and media.
|
||||
- Sets ownership of the directories.
|
||||
- Mounts NFS shares.
|
||||
5. **Deploy configs**:
|
||||
- Sets up Keycloak realms if the host is a Keycloak host.
|
||||
6. **Deploy Docker Compose**:
|
||||
- Copies the Docker Compose file to the target host.
|
||||
7. **Publish metrics**:
|
||||
- Copies the `daemon.json` file to `/etc/docker/daemon.json` to enable metrics.
|
||||
|
||||
## Handlers
|
||||
|
||||
- `Restart docker`: Restarts the Docker service.
|
||||
- `Restart compose`: Restarts the Docker Compose services.
|
||||
- `Restart host`: Reboots the host.
|
||||
|
||||
## Usage
|
||||
|
||||
To use this role, include it in your playbook and set the required variables.
|
||||
|
||||
```yaml
|
||||
- hosts: docker_hosts
|
||||
roles:
|
||||
- role: docker_host
|
||||
vars:
|
||||
# Your variables here
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -8,14 +8,4 @@
|
||||
- name: Restart compose
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ docker.directories.compose }}"
|
||||
state: present
|
||||
retries: 3
|
||||
delay: 5
|
||||
become: true
|
||||
|
||||
- name: Restart host
|
||||
ansible.builtin.reboot:
|
||||
connect_timeout: 5
|
||||
reboot_timeout: 600
|
||||
test_command: whoami
|
||||
become: true
|
||||
state: restarted
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
- name: Check if debian.sources file exists
|
||||
ansible.builtin.stat:
|
||||
path: /etc/apt/sources.list.d/debian.sources
|
||||
register: debian_sources_stat
|
||||
|
||||
- name: Replace Components line to include non-free and non-free-firmware
|
||||
ansible.builtin.replace:
|
||||
path: /etc/apt/sources.list.d/debian.sources
|
||||
regexp: "^Components:.*$"
|
||||
replace: "Components: main non-free non-free-firmware"
|
||||
when: debian_sources_stat.stat.exists
|
||||
become: true
|
||||
|
||||
- name: Setup VM Packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
update_cache: true
|
||||
loop: "{{ docker_host_package_common_dependencies }}"
|
||||
become: true
|
||||
|
||||
- name: Gather installed package facts
|
||||
ansible.builtin.package_facts:
|
||||
manager: auto
|
||||
|
||||
- name: Filter for specific cloud kernel packages
|
||||
ansible.builtin.set_fact:
|
||||
cloud_kernel_packages: >-
|
||||
{{
|
||||
ansible_facts.packages.keys()
|
||||
| select('search', 'linux-image')
|
||||
| select('search', 'cloud')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Use the list to remove the found packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ cloud_kernel_packages }}"
|
||||
state: absent
|
||||
autoremove: true
|
||||
when: cloud_kernel_packages | length > 0
|
||||
become: true
|
||||
|
||||
- name: Restart host
|
||||
ansible.builtin.reboot:
|
||||
connect_timeout: 5
|
||||
reboot_timeout: 600
|
||||
test_command: whoami
|
||||
become: true
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
- name: Set fact if this host should run Keycloak
|
||||
ansible.builtin.set_fact:
|
||||
is_keycloak_host: "{{ inventory_hostname in (services | selectattr('name', 'equalto', 'keycloak') | map(attribute='vm') | first) }}"
|
||||
|
||||
- name: Create Keycloak directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ docker.directories.local }}/keycloak/"
|
||||
owner: "{{ ansible_user_id }}"
|
||||
group: "{{ ansible_user_id }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
when: is_keycloak_host | bool
|
||||
become: true
|
||||
|
||||
- name: Setup Keycloak realms
|
||||
ansible.builtin.template:
|
||||
src: "templates/keycloak/realm.json.j2"
|
||||
dest: "{{ docker.directories.local }}/keycloak/{{ keycloak.realm }}-realm.json"
|
||||
owner: "{{ ansible_user_id }}"
|
||||
group: "{{ ansible_user_id }}"
|
||||
mode: "644"
|
||||
backup: true
|
||||
when: is_keycloak_host | bool
|
||||
loop: "{{ keycloak_config.realms }}"
|
||||
loop_control:
|
||||
loop_var: keycloak
|
||||
notify:
|
||||
- Restart docker
|
||||
- Restart compose
|
||||
become: true
|
||||
@@ -3,8 +3,8 @@
|
||||
ansible.builtin.template:
|
||||
src: "templates/compose.yaml.j2"
|
||||
dest: "{{ docker.directories.compose }}/compose.yaml"
|
||||
owner: "{{ ansible_user_id }}"
|
||||
group: "{{ ansible_user_id }}"
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
mode: "644"
|
||||
backup: true
|
||||
notify:
|
||||
@@ -5,23 +5,23 @@
|
||||
state: directory
|
||||
mode: "0755"
|
||||
loop:
|
||||
- /media/docker
|
||||
- /media/series
|
||||
- /media/movies
|
||||
- /media/songs
|
||||
- "{{ docker.directories.local }}"
|
||||
- "{{ docker.directories.config }}"
|
||||
- "{{ docker.directories.opt }}"
|
||||
- "{{ docker.directories.compose }}"
|
||||
- /opt/local
|
||||
become: true
|
||||
|
||||
- name: Set ownership to {{ ansible_user_id }}
|
||||
- name: Set ownership to {{ user }}
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
owner: "{{ ansible_user_id }}"
|
||||
group: "{{ ansible_user_id }}"
|
||||
owner: "{{ user }}"
|
||||
group: "{{ user }}"
|
||||
loop:
|
||||
- "{{ docker.directories.local }}"
|
||||
- "{{ docker.directories.config }}"
|
||||
- "{{ docker.directories.compose }}"
|
||||
- "{{ docker.directories.opt }}"
|
||||
- /opt/local
|
||||
- /media
|
||||
become: true
|
||||
|
||||
@@ -37,5 +37,4 @@
|
||||
- /media/series
|
||||
- /media/movies
|
||||
- /media/songs
|
||||
- /media/downloads
|
||||
become: true
|
||||
@@ -26,7 +26,6 @@
|
||||
- curl
|
||||
- gnupg
|
||||
- lsb-release
|
||||
- qemu-guest-agent
|
||||
become: true
|
||||
|
||||
- name: Add Docker apt key.
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
- name: Setup VM
|
||||
ansible.builtin.include_tasks: 10_setup.yaml
|
||||
|
||||
- name: Install docker
|
||||
ansible.builtin.include_tasks: 20_installation.yaml
|
||||
|
||||
- name: Setup user and group for docker
|
||||
ansible.builtin.include_tasks: 30_user_group_setup.yaml
|
||||
|
||||
- name: Setup directory structure for docker
|
||||
ansible.builtin.include_tasks: 40_directory_setup.yaml
|
||||
|
||||
# - name: Deploy configs
|
||||
# ansible.builtin.include_tasks: 50_provision.yaml
|
||||
|
||||
- name: Deploy docker compose
|
||||
ansible.builtin.include_tasks: 60_deploy_compose.yaml
|
||||
|
||||
- name: Publish metrics
|
||||
ansible.builtin.include_tasks: 70_export.yaml
|
||||
18
roles/docker_host/tasks/main.yml
Normal file
18
roles/docker_host/tasks/main.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
- name: Setup VM
|
||||
ansible.builtin.include_tasks: setup.yml
|
||||
|
||||
- name: Install docker
|
||||
ansible.builtin.include_tasks: installation.yml
|
||||
|
||||
- name: Setup user and group for docker
|
||||
ansible.builtin.include_tasks: user_group_setup.yml
|
||||
|
||||
- name: Setup directory structure for docker
|
||||
ansible.builtin.include_tasks: directory_setup.yml
|
||||
|
||||
- name: Deploy docker compose
|
||||
ansible.builtin.include_tasks: deploy_compose.yml
|
||||
|
||||
- name: Publish metrics
|
||||
ansible.builtin.include_tasks: export.yml
|
||||
9
roles/docker_host/tasks/setup.yml
Normal file
9
roles/docker_host/tasks/setup.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: Enable HW accelerate for VM
|
||||
ansible.builtin.apt:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
loop:
|
||||
- firmware-misc-nonfree
|
||||
- nfs-common
|
||||
become: true
|
||||
@@ -5,12 +5,10 @@
|
||||
state: present
|
||||
become: true
|
||||
|
||||
- name: Append the group docker to "{{ ansible_user_id }}"
|
||||
- name: Append the group docker to "{{ user }}"
|
||||
ansible.builtin.user:
|
||||
name: "{{ ansible_user_id }}"
|
||||
name: "{{ user }}"
|
||||
shell: /bin/bash
|
||||
groups: docker
|
||||
append: true
|
||||
become: true
|
||||
notify:
|
||||
- Restart host
|
||||
@@ -1,13 +1,12 @@
|
||||
services:
|
||||
{% for service in services %}
|
||||
{% if inventory_hostname in service.vm %}
|
||||
|
||||
{{ service.name }}:
|
||||
{{service.name}}:
|
||||
container_name: {{ service.container_name }}
|
||||
image: {{ service.image }}
|
||||
restart: unless-stopped
|
||||
restart: {{ service.restart }}
|
||||
{% if service.network_mode is not defined %}
|
||||
hostname: {{ service.name }}
|
||||
hostname: {{service.name}}
|
||||
networks:
|
||||
- net
|
||||
{% endif %}
|
||||
@@ -16,40 +15,11 @@ services:
|
||||
ports:
|
||||
{% for port in service.ports %}
|
||||
{% if port.internal != 'proxy_only' %}
|
||||
- {{ port.external }}:{{ port.internal }}
|
||||
- {{port.external}}:{{port.internal}}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if service.ports is defined and service.ports is iterable %}
|
||||
{% set first_http_port = service.ports | default([]) | selectattr('name', 'defined') | selectattr('name', 'search', 'http') | first %}
|
||||
{% set chosen_http_port_value = none %}
|
||||
{% if first_http_port is not none %}
|
||||
{% if first_http_port.internal is defined and first_http_port.internal == 'proxy_only' %}
|
||||
{% if first_http_port.external is defined %}
|
||||
{% set chosen_http_port_value = first_http_port.external %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% set chosen_http_port_value = first_http_port.internal %}
|
||||
{% endif %}
|
||||
{% if chosen_http_port_value is defined %}
|
||||
healthcheck:
|
||||
{% set healthcheck = 'curl' %}
|
||||
{% if service.healthcheck is defined %}
|
||||
{% set healthcheck = service.healthcheck %}
|
||||
{% endif %}
|
||||
{% if healthcheck == 'curl' %}
|
||||
test: ["CMD", "curl", "-f", "--silent", "--show-error", "--connect-timeout", "5", "http://localhost:{{ chosen_http_port_value }}/"]
|
||||
{% elif healthcheck == 'wget' %}
|
||||
test: ["CMD-SHELL", "wget --quiet --spider --timeout=5 http://localhost:{{ chosen_http_port_value }}/ || exit 1"]
|
||||
{% endif %}
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 20s
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if service.cap_add is defined and service.cap_add is iterable %}
|
||||
cap_add:
|
||||
{% for cap in service.cap_add %}
|
||||
@@ -71,88 +41,46 @@ services:
|
||||
{% if service.volumes is defined and service.volumes is iterable %}
|
||||
volumes:
|
||||
{% for volume in service.volumes %}
|
||||
- {{ volume.external }}:{{ volume.internal }}
|
||||
- {{volume.external}}:{{volume.internal}}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if service.environment is defined and service.environment is iterable %}
|
||||
environment:
|
||||
{% for env in service.environment %}
|
||||
- {{ env }}
|
||||
- {{env}}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if service.devices is defined and service.devices is iterable %}
|
||||
devices:
|
||||
{% for device in service.devices %}
|
||||
- {{ device.external }}:{{ device.internal }}
|
||||
- {{device.external}}:{{device.internal}}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if service.command is defined and service.command is iterable %}
|
||||
command:
|
||||
{% for command in service.command %}
|
||||
- {{ command }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if service.sub_service is defined and service.sub_service is iterable %}
|
||||
{% for sub in service.sub_service %}
|
||||
{% if sub.name is defined and sub.name == "postgres" %}
|
||||
{{ service.name }}-postgres:
|
||||
container_name: {{ service.name }}-postgres
|
||||
image: docker.io/library/postgres:{{ sub.version }}
|
||||
{% if service.name == 'paperless' %}
|
||||
|
||||
{{service.name}}-broker:
|
||||
container_name: paperless-broker
|
||||
image: docker.io/library/redis:7
|
||||
restart: unless-stopped
|
||||
hostname: {{ service.name }}-postgres
|
||||
networks:
|
||||
- net
|
||||
volumes:
|
||||
- /opt/local/{{ service.name }}/postgres/data:/var/lib/postgresql/data
|
||||
- /opt/local/paperless/redis/data:/data
|
||||
|
||||
{{service.name}}-postgres:
|
||||
container_name: paperless-postgres
|
||||
image: docker.io/library/postgres:15
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- net
|
||||
volumes:
|
||||
- /opt/local/paperless/db/data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: {{ service.name }}
|
||||
POSTGRES_USER: {{ sub.username }}
|
||||
POSTGRES_PASSWORD: {{ sub.password }}
|
||||
{% endif %}
|
||||
{% if sub.name is defined and sub.name == "redis" %}
|
||||
{{ service.name }}-redis:
|
||||
container_name: {{ service.name }}-redis
|
||||
image: docker.io/library/redis:{{ sub.version }}
|
||||
restart: unless-stopped
|
||||
hostname: {{ service.name }}-redis
|
||||
networks:
|
||||
- net
|
||||
volumes:
|
||||
- /opt/local/{{ service.name }}/redis/data:/data
|
||||
{% endif %}
|
||||
{% if sub.name is defined and sub.name == "chrome" %}
|
||||
{{ service.name }}-chrome:
|
||||
image: gcr.io/zenika-hub/alpine-chrome:{{ sub.version }}
|
||||
container_name: {{ service.name }}-chrome
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- net
|
||||
command:
|
||||
- --no-sandbox
|
||||
- --disable-gpu
|
||||
- --disable-dev-shm-usage
|
||||
- --remote-debugging-address=0.0.0.0
|
||||
- --remote-debugging-port=9222
|
||||
- --hide-scrollbars
|
||||
{% endif %}
|
||||
{% if sub.name is defined and sub.name == "meilisearch" %}
|
||||
{{ service.name }}-meilisearch:
|
||||
container_name: {{ service.name }}-meilisearch
|
||||
image: getmeili/meilisearch:{{ sub.version }}
|
||||
restart: unless-stopped
|
||||
hostname: {{ service.name }}-meilisearch
|
||||
networks:
|
||||
- net
|
||||
volumes:
|
||||
- /opt/local/{{ service.name }}/mailisearch/data:/meili_data
|
||||
environment:
|
||||
- MEILI_NO_ANALYTICS=true
|
||||
- NEXTAUTH_SECRET={{ sub.nextauth_secret }}
|
||||
- MEILI_MASTER_KEY={{ sub.meili_master_key }}
|
||||
- OPENAI_API_KEY="{{ sub.openai_key }}"
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
POSTGRES_DB: paperless
|
||||
POSTGRES_USER: paperless
|
||||
POSTGRES_PASSWORD: 5fnhn%u2YWY3paNvMAjdoufYPQ2Hf3Yi
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
networks:
|
||||
@@ -162,3 +90,6 @@ networks:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: 172.16.69.0/24
|
||||
|
||||
volumes:
|
||||
prometheus_data: {}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
{
|
||||
"realm": "{{ keycloak.realm }}",
|
||||
"enabled": true,
|
||||
"displayName": "{{ keycloak.display_name }}",
|
||||
"displayNameHtml": "<div class=\"kc-logo-text\">{{keycloak.display_name}}</div>",
|
||||
"bruteForceProtected": true,
|
||||
"users": [
|
||||
{% if keycloak.users is defined and keycloak.users is iterable %}
|
||||
{% for user in keycloak.users %}
|
||||
{
|
||||
"username": "{{ user.username }}",
|
||||
"enabled": true,
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "{{ user.password }}",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
{% for realm_role in user.realm_roles %}
|
||||
"{{ realm_role }}"{%- if not loop.last %},{% endif %}{{''}}
|
||||
{% endfor %}
|
||||
],
|
||||
"clientRoles": {
|
||||
"account": [
|
||||
{% for account in user.client_roles.account %}
|
||||
"{{ account }}"{%- if not loop.last %},{% endif %}{{''}}
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
},{% if not loop.last %}{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{
|
||||
"username": "{{ keycloak.admin.username }}",
|
||||
"enabled": true,
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "{{ keycloak.admin.password }}",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
{% for realm_role in keycloak.admin.realm_roles %}
|
||||
"{{ realm_role }}"{% if not loop.last %},{% endif %}{{''}}
|
||||
{% endfor %}
|
||||
],
|
||||
"clientRoles": {
|
||||
"realm-management": [
|
||||
{% for realm_management in keycloak.admin.client_roles.realm_management %}
|
||||
"{{ realm_management }}"{%- if not loop.last %},{% endif %}{{''}}
|
||||
{% endfor %}
|
||||
],
|
||||
"account": [
|
||||
{% for account in keycloak.admin.client_roles.account %}
|
||||
"{{ account }}"{%- if not loop.last %},{% endif %}{{''}}
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"roles": {
|
||||
"realm": [
|
||||
{% for role in keycloak.roles.realm %}
|
||||
{
|
||||
"name": "{{ role.name }}",
|
||||
"description": "{{ role.name }}"
|
||||
}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
]
|
||||
},
|
||||
"defaultRoles": [
|
||||
{% for role in keycloak.roles.default_roles %}
|
||||
"{{ role }}"{% if not loop.last %},{% endif %}{{''}}
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
docker_host_package_common_dependencies:
|
||||
- nfs-common
|
||||
|
||||
apt_lock_files:
|
||||
- /var/lib/dpkg/lock
|
||||
- /var/lib/dpkg/lock-frontend
|
||||
- /var/cache/apt/archives/lock
|
||||
@@ -1,75 +0,0 @@
|
||||
# Edge VPS
|
||||
|
||||
Configures edge VPS instances with WireGuard VPN, Traefik reverse proxy, Pangolin, and Elastic Fleet Agent.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- Ansible community.docker collection
|
||||
|
||||
## Role Variables
|
||||
|
||||
### WireGuard
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `edge_vps_wireguard_address` | `10.133.7.1/24` | WireGuard interface address |
|
||||
| `edge_vps_wireguard_port` | `61975` | WireGuard listen port |
|
||||
| `edge_vps_wireguard_interface` | `wg0` | WireGuard interface name |
|
||||
| `edge_vps_wireguard_routes` | `[]` | List of routes to add (network, gateway) |
|
||||
|
||||
### Traefik
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `edge_vps_traefik_config_dir` | `/root/config/traefik` | Traefik config directory |
|
||||
| `edge_vps_acme_email` | - | Email for Let's Encrypt |
|
||||
|
||||
### Pangolin
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `edge_vps_pangolin_dashboard_url` | - | Pangolin dashboard URL |
|
||||
| `edge_vps_pangolin_base_endpoint` | - | Pangolin base endpoint |
|
||||
| `edge_vps_pangolin_base_domain` | - | Base domain for Pangolin |
|
||||
|
||||
### Elastic Agent
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `edge_vps_elastic_version` | `9.2.2` | Elastic Agent version |
|
||||
| `edge_vps_elastic_fleet_url` | - | Fleet server URL |
|
||||
| `edge_vps_elastic_dns_server` | `10.43.0.10` | DNS server for agent |
|
||||
|
||||
## Secrets
|
||||
|
||||
Store secrets in `vars/group_vars/vps/secrets.yaml` (ansible-vault encrypted):
|
||||
|
||||
```yaml
|
||||
vault_edge_vps:
|
||||
wireguard:
|
||||
private_key: "..."
|
||||
peers: [...]
|
||||
pangolin:
|
||||
server_secret: "..."
|
||||
traefik:
|
||||
cloudflare_api_token: "..."
|
||||
elastic:
|
||||
fleet_enrollment_token: "..."
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Example Playbook
|
||||
|
||||
```yaml
|
||||
- hosts: vps
|
||||
roles:
|
||||
- role: edge_vps
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
edge_vps_config_base: /root/config
|
||||
edge_vps_wireguard_config_dir: /etc/wireguard
|
||||
edge_vps_wireguard_interface: wg0
|
||||
edge_vps_wireguard_address: "10.133.7.1/24"
|
||||
edge_vps_wireguard_port: 61975
|
||||
edge_vps_traefik_config_dir: "{{ edge_vps_config_base }}/traefik"
|
||||
edge_vps_traefik_logs_dir: "{{ edge_vps_traefik_config_dir }}/logs"
|
||||
edge_vps_pangolin_config_dir: "{{ edge_vps_config_base }}/pangolin"
|
||||
edge_vps_elastic_config_dir: "{{ edge_vps_config_base }}/elastic-agent"
|
||||
edge_vps_elastic_state_dir: /var/lib/elastic-agent/elastic-system/elastic-agent/state
|
||||
@@ -1,20 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDVjCCAj6gAwIBAgIRAPcoBHrxSnovxGFQ44+7XiYwDQYJKoZIhvcNAQELBQAw
|
||||
NTEWMBQGA1UECxMNZWxhc3RpY3NlYXJjaDEbMBkGA1UEAxMSZWxhc3RpY3NlYXJj
|
||||
aC1odHRwMB4XDTI2MDIwOTIxNDI0NVoXDTI3MDIwOTIxNTI0NVowNTEWMBQGA1UE
|
||||
CxMNZWxhc3RpY3NlYXJjaDEbMBkGA1UEAxMSZWxhc3RpY3NlYXJjaC1odHRwMIIB
|
||||
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA48M932+yPFJkVg31G5f1jJ1g
|
||||
IevD+tujYp96De3MY/5QNEsW1R21VWwAobfSN+3NyInhjXT03IhXIwN21B0KPTtO
|
||||
c6cpOk0/nwmF0pHpK1PLaqvsfUsa4ffSRvwpsSA0rlEoF+ObBUuQ92ngvAXMN3wp
|
||||
PhcaNw9zbPidJoUjwzeaL3nmgnXQIBFRqYGi6l5LzVA0qVHXsNHi5LgXPN4wevWs
|
||||
49kn9xPYPXrYBMLxn7hPa9/OfRjUtru2ZoK7L1imr86tjppY0rk8GxIHF12eVf4t
|
||||
nGeDUMBuYe6mmUTTkFiwYmrwTzhfDlN82wZ+6cmYeDxpce2nbLBTMICJYOJmMwID
|
||||
AQABo2EwXzAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
|
||||
AQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHvrdY9Nbr77PnHkkEiD
|
||||
Y79yBXpkMA0GCSqGSIb3DQEBCwUAA4IBAQCS3X8dQYD89rrltR7HjrG4KCtG6uDY
|
||||
U3LYSu1KCBiwMIwYn6RZoI+6D7t16AOumwJC3AJ3/JFkGr7F+UqQSYIaAxYEeyzS
|
||||
c2oPzl52h1tbfKUS/550FhWqFuOG6m6SCFSUXe17ShPoomtBxvFjJr6fZLezKdoO
|
||||
CBZX0PzHCnU7axFLoNHqzl55koxVcyaY8OjcjvsuAP5zU77nF4sSoHtZ3VTprGWE
|
||||
xL3j+vFJ4++d516frWVY8L20mECOcDfLXEf3ngmK9j+8v7UwwpPxWe9MlLS+v7QH
|
||||
yBuAMUyKymN4zzhIVKSSYZmiwdkzwUIykffphymJVAQCDSXgX4RWPuKi
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,20 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDUjCCAjqgAwIBAgIRANgLvsSqUxkRAC8fvlBQsn4wDQYJKoZIhvcNAQELBQAw
|
||||
MzEVMBMGA1UECxMMZmxlZXQtc2VydmVyMRowGAYDVQQDExFmbGVldC1zZXJ2ZXIt
|
||||
aHR0cDAeFw0yNjAyMDkyMTQyNDhaFw0yNzAyMDkyMTUyNDhaMDMxFTATBgNVBAsT
|
||||
DGZsZWV0LXNlcnZlcjEaMBgGA1UEAxMRZmxlZXQtc2VydmVyLWh0dHAwggEiMA0G
|
||||
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0zbNbwm3YnaNKQbmHb/9fk5YadGop
|
||||
9d9n0VA7pYC32qST5/IsWAkTP/ulPfJwI+nA18tAqtBoLMncdpKP9YtMb1cgRNGe
|
||||
d9Fe1kItmIGxoYlQPx4vbbembyvlFFEu82/4tJtDkCR5TuP3ZdmGWazO+tGooMvL
|
||||
vkKy0qgQEDUIPTF1VFHcQa+qRvIerAKV81q2lVluVr/GNljoISsXgsoHXG2MDPDs
|
||||
RHX+XcQGFNlFG1MuiGApvrKSFsFTCxn8oM88waoI0t/D+y7T1WNwLRY+Fg6fivVh
|
||||
kNaIPuCswAIB0MLATtPDP85IjKMxEk5/cTz5R1jOsYz1OoIydkSN87tDAgMBAAGj
|
||||
YTBfMA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
|
||||
AwIwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUNRhWtaWRi0nubx9yz3tXMDaz
|
||||
2AIwDQYJKoZIhvcNAQELBQADggEBAFwFlEQ26vdbPtTv5gpIIRAZDcYAGtm6wx16
|
||||
/dqedcVXKSbKKPJq1OfHjYSfN3r3XGGLKTlui8v7Pkz/bqQyAONEC+4S33RX3MiT
|
||||
3zTu/SLHiOyHfdLn44Z8JUZ6xmK3mSfchngKLRlECHjNydzYtzJSj67CP7ARJhHo
|
||||
wOlQwH11EC+HLrhYBeW4si5L5jCnE9rpKQ4U+/MCLgpdWtHZ3G3PVFxBjL8JISLP
|
||||
ZZnHwCMK1LiuWtY3+n3S6BqDDgrQg0TsVA8X/tdEQKzoJb0hTwKrGpvy7CO42vLf
|
||||
X+h9iUG4QNve+QCT2Y7T9jNTaWamTHfZWFa6FD5CEgldqDJfEZw=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
- name: Restart wireguard
|
||||
ansible.builtin.systemd:
|
||||
name: "wg-quick@{{ edge_vps_wireguard_interface }}"
|
||||
state: restarted
|
||||
listen: restart wireguard
|
||||
|
||||
- name: Restart traefik
|
||||
ansible.builtin.command:
|
||||
cmd: docker compose restart
|
||||
chdir: "{{ edge_vps_traefik_config_dir }}"
|
||||
listen: restart traefik
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
- name: Create config base directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ edge_vps_config_base }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Create Traefik directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
loop:
|
||||
- "{{ edge_vps_traefik_config_dir }}"
|
||||
- "{{ edge_vps_traefik_logs_dir }}"
|
||||
|
||||
- name: Create Pangolin config directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ edge_vps_pangolin_config_dir }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Create Elastic Agent directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
loop:
|
||||
- "{{ edge_vps_elastic_config_dir }}"
|
||||
- "{{ edge_vps_elastic_state_dir }}"
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
- name: Install WireGuard
|
||||
ansible.builtin.apt:
|
||||
name: wireguard
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Deploy WireGuard config
|
||||
ansible.builtin.template:
|
||||
src: wireguard/wg0.conf.j2
|
||||
dest: "{{ edge_vps_wireguard_config_dir }}/{{ edge_vps_wireguard_interface }}.conf"
|
||||
mode: "0600"
|
||||
notify: restart wireguard
|
||||
|
||||
- name: Enable WireGuard
|
||||
ansible.builtin.systemd:
|
||||
name: "wg-quick@{{ edge_vps_wireguard_interface }}"
|
||||
enabled: true
|
||||
state: started
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
- name: Deploy Traefik config
|
||||
ansible.builtin.template:
|
||||
src: traefik/traefik_config.yml.j2
|
||||
dest: "{{ edge_vps_traefik_config_dir }}/traefik_config.yml"
|
||||
mode: "0644"
|
||||
notify: restart traefik
|
||||
|
||||
- name: Deploy Cloudflare credentials for ACME
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
CF_DNS_API_TOKEN={{ vault_edge_vps.traefik.cloudflare_api_token }}
|
||||
dest: "{{ edge_vps_traefik_config_dir }}/cloudflare.env"
|
||||
mode: "0600"
|
||||
no_log: true
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
- name: Deploy Pangolin config
|
||||
ansible.builtin.template:
|
||||
src: pangolin/config.yml.j2
|
||||
dest: "{{ edge_vps_pangolin_config_dir }}/config.yml"
|
||||
mode: "0644"
|
||||
notify: restart pangolin
|
||||
|
||||
- name: Deploy Pangolin docker-compose
|
||||
ansible.builtin.template:
|
||||
src: pangolin/docker-compose.yml.j2
|
||||
dest: "{{ edge_vps_pangolin_config_dir }}/docker-compose.yml"
|
||||
mode: "0644"
|
||||
|
||||
- name: Create letsencrypt directory for Pangolin
|
||||
ansible.builtin.file:
|
||||
path: "{{ edge_vps_pangolin_config_dir }}/letsencrypt"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Start Pangolin
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ edge_vps_pangolin_config_dir }}"
|
||||
state: present
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
- name: Deploy Elastic Agent config
|
||||
ansible.builtin.template:
|
||||
src: elastic-agent/elastic-agent.yml.j2
|
||||
dest: "{{ edge_vps_elastic_config_dir }}/elastic-agent.yml"
|
||||
mode: "0644"
|
||||
|
||||
- name: Deploy Elastic Agent docker-compose
|
||||
ansible.builtin.template:
|
||||
src: elastic-agent/docker-compose.yml.j2
|
||||
dest: "{{ edge_vps_elastic_config_dir }}/docker-compose.yml"
|
||||
mode: "0644"
|
||||
|
||||
- name: Deploy Elasticsearch CA certificate
|
||||
ansible.builtin.copy:
|
||||
src: elastic-agent/elasticsearch-ca.crt
|
||||
dest: "{{ edge_vps_elastic_config_dir }}/elasticsearch-ca.crt"
|
||||
mode: "0644"
|
||||
|
||||
- name: Deploy Fleet CA certificate
|
||||
ansible.builtin.copy:
|
||||
src: elastic-agent/fleet-ca.crt
|
||||
dest: "{{ edge_vps_elastic_config_dir }}/fleet-ca.crt"
|
||||
mode: "0644"
|
||||
|
||||
- name: Start Elastic Agent
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ edge_vps_elastic_config_dir }}"
|
||||
state: present
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user