Compare commits
65 Commits
elastic_se
...
a9346881b0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9346881b0 | ||
|
|
193da30e65 | ||
|
|
9a5cb376bd | ||
|
|
fc2eefdfb0 | ||
|
|
274b9c310e | ||
|
|
6fdd021604 | ||
|
|
1b82acad1f | ||
|
|
d8822ad904 | ||
|
|
caecfc7c1d | ||
|
|
4907761649 | ||
|
|
a3cb1928ae | ||
|
|
99f6876ce9 | ||
|
|
0a3171b9bc | ||
|
|
3068a5a8fb | ||
|
|
ef652fac20 | ||
|
|
22c1b534ab | ||
|
|
9cb90a8020 | ||
|
|
d9181515bb | ||
|
|
c3905ed144 | ||
|
|
5fb50ab4b2 | ||
|
|
2909d6e16c | ||
|
|
0aed818be5 | ||
|
|
fbdeec93ce | ||
|
|
44626101de | ||
|
|
c1d6f13275 | ||
|
|
282e98e90a | ||
|
|
9573cbfcad | ||
|
|
48aec11d8c | ||
|
|
a1da69ac98 | ||
|
|
7aa16f3207 | ||
|
|
fe3f1749c5 | ||
|
|
6eef96b302 | ||
|
|
2882abfc0b | ||
|
|
2b759cc2ab | ||
|
|
dbaebaee80 | ||
|
|
89c51aa45c | ||
|
|
0139850ee3 | ||
|
|
976cad51e2 | ||
|
|
e1a2248154 | ||
|
|
d8fd094379 | ||
|
|
76000f8123 | ||
|
|
4aa939426b | ||
|
|
9cce71f73b | ||
|
|
97a5d6c41d | ||
|
|
f1b0cfad2c | ||
|
|
dac0d88d60 | ||
|
|
609e000089 | ||
|
|
3d7f652ff3 | ||
|
|
cb8ccd8f00 | ||
|
|
02168225b1 | ||
|
|
6ff1ccecd0 | ||
|
|
de62327fde | ||
|
|
b70c8408dc | ||
|
|
a913e1cbc0 | ||
|
|
e3c67a32e9 | ||
|
|
8f2998abc0 | ||
|
|
7fcee3912f | ||
|
|
591342f580 | ||
|
|
f2ea03bc01 | ||
|
|
0e8e07ed3e | ||
|
|
a2a58f6343 | ||
|
|
42196a32dc | ||
|
|
6934a9f5fc | ||
|
|
27621aac03 | ||
|
|
56f058c254 |
33
.ansible-lint
Normal file
33
.ansible-lint
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
# .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
|
||||||
17
.editorconfig
Normal file
17
.editorconfig
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
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
Normal file
8
.gitattributes
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
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
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -0,0 +1 @@
|
|||||||
|
.worktrees/
|
||||||
|
|||||||
23
.pre-commit-config.yaml
Normal file
23
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
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
|
||||||
116
README.md
116
README.md
@@ -1,74 +1,82 @@
|
|||||||
# TuDatTr IaC
|
# TuDatTr IaC
|
||||||
|
|
||||||
**I do not recommend this project being used for ones own infrastructure, as
|
**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.**
|
||||||
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).
|
|
||||||
|
|
||||||
## Prerequisites
|
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.
|
||||||
|
|
||||||
- [secrets.yml](secrets.yml) in the root directory of this repository.
|
## Repository Structure
|
||||||
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.
|
|
||||||
|
|
||||||
## Improvable Variables
|
The repository is organized into the following main directories:
|
||||||
|
|
||||||
- `group_vars/k3s/vars.yml`:
|
- `playbooks/`: Contains the main Ansible playbooks for different setup scenarios.
|
||||||
- `k3s.server.ips`: Take list of IPs from host_vars `k3s_server*.yml`.
|
- `roles/`: Contains the Ansible roles that are used by the playbooks.
|
||||||
- `k3s_db_connection_string`: Embed this variable in the `k3s.db.`-directory.
|
- `vars/`: Contains variable files, including group-specific variables.
|
||||||
Currently causes loop.
|
|
||||||
|
|
||||||
## Run Playbook
|
## Playbooks
|
||||||
|
|
||||||
To run a first playbook and test the setup the following command can be executed.
|
The following playbooks are available:
|
||||||
|
|
||||||
```sh
|
- `proxmox.yml`: Provisions VMs and containers on Proxmox VE.
|
||||||
ansible-playbook -i production -J k3s-servers.yml
|
- `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
|
||||||
```
|
```
|
||||||
|
|
||||||
This will run the [./k3s-servers.yml](./k3s-servers.yml) playbook and execute
|
2. **Configure variables:**
|
||||||
its roles.
|
|
||||||
|
|
||||||
## After successful k3s installation
|
- Create an inventory file (e.g., `vars/k3s.ini`).
|
||||||
|
- Adjust variables in `vars/group_vars/` to match your environment.
|
||||||
|
|
||||||
To access our Kubernetes cluster from our host machine to work on it via
|
3. **Run playbooks:**
|
||||||
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
|
```bash
|
||||||
mkdir ~/.kube/
|
# To provision VMs on Proxmox
|
||||||
scp k3s-server00:/etc/rancher/k3s/k3s.yaml ~/.kube/config
|
ansible-playbook -i vars/proxmox.ini playbooks/proxmox.yml
|
||||||
chown $USER ~/.kube/config
|
|
||||||
sed -i "s/127.0.0.1/192.168.20.22/" ~/.kube/config
|
# To set up the K3s cluster
|
||||||
export KUBECONFIG=~/.kube/config
|
ansible-playbook -i vars/k3s.ini playbooks/kubernetes_setup.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
Install flux and continue in the flux repository.
|
## Notes
|
||||||
|
|
||||||
## Longhorn Nodes
|
### Vault Git Diff
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
|
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
|
```sh
|
||||||
# Create a new partition from the free space.
|
# https://stackoverflow.com/questions/29937195/how-to-diff-ansible-vault-changes
|
||||||
sudo fdisk /dev/sda
|
git config --global diff.ansible-vault.textconv "ansible-vault view"
|
||||||
# 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
This project is highly customized for the author's specific environment. Using it without modification is not recommended.
|
||||||
|
|||||||
31
Vagrantfile
vendored
31
Vagrantfile
vendored
@@ -1,31 +0,0 @@
|
|||||||
# -*- 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,9 +1,12 @@
|
|||||||
[defaults]
|
[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.
|
# (pathspec) Colon separated paths in which Ansible will search for Roles.
|
||||||
roles_path=./roles
|
roles_path=./roles
|
||||||
|
|
||||||
# (pathlist) Comma separated list of Ansible inventory sources
|
# (pathlist) Comma separated list of Ansible inventory sources
|
||||||
inventory=./inventory/production
|
inventory=./vars/
|
||||||
|
|
||||||
# (path) The vault password file to use. Equivalent to --vault-password-file or --vault-id
|
# (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.
|
# If executable, it will be run and the resulting stdout will be used as the password.
|
||||||
@@ -11,7 +14,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.
|
# (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.
|
# This affects vars_files, include_vars, inventory and vars plugins among others.
|
||||||
yaml_valid_extensions=.yml
|
yaml_valid_extensions=.yaml
|
||||||
|
|
||||||
# (boolean) Set this to "False" if you want to avoid host key checking by the underlying tools Ansible uses to connect to the host
|
# (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
|
host_key_checking=False
|
||||||
@@ -33,3 +36,6 @@ skip=dark gray
|
|||||||
[tags]
|
[tags]
|
||||||
# (list) default list of tags to skip in your plays, has precedence over Run Tags
|
# (list) default list of tags to skip in your plays, has precedence over Run Tags
|
||||||
;skip=
|
;skip=
|
||||||
|
|
||||||
|
[inventory]
|
||||||
|
ignore_extensions={{(REJECT_EXTS + ('.orig', '.cfg', '.retry', '.bak'))}}
|
||||||
|
|||||||
@@ -688,4 +688,3 @@
|
|||||||
|
|
||||||
# (list) default list of tags to skip in your plays, has precedence over Run Tags
|
# (list) default list of tags to skip in your plays, has precedence over Run Tags
|
||||||
;skip=
|
;skip=
|
||||||
|
|
||||||
|
|||||||
69
blog.md
Normal file
69
blog.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
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
Normal file
75
changelog.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# 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.
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
$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
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#
|
|
||||||
# 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' }}"
|
|
||||||
@@ -1,532 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
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 }}"
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
[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"'
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
[local]
|
|
||||||
test ansible_connection=local ansible_become_pass=vagrant
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Run the common role on k3s
|
|
||||||
hosts: k3s
|
|
||||||
gather_facts: yes
|
|
||||||
vars_files:
|
|
||||||
- secrets.yml
|
|
||||||
roles:
|
|
||||||
- role: common
|
|
||||||
tags:
|
|
||||||
- common
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
- 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,13 +1,11 @@
|
|||||||
---
|
---
|
||||||
- name: Set up Servers
|
- name: Set up Servers
|
||||||
hosts: docker_host
|
hosts: docker_host
|
||||||
gather_facts: yes
|
gather_facts: true
|
||||||
vars_files:
|
|
||||||
- secrets.yml
|
|
||||||
roles:
|
roles:
|
||||||
- role: common
|
# - role: common
|
||||||
tags:
|
# tags:
|
||||||
- common
|
# - common
|
||||||
- role: docker_host
|
- role: docker_host
|
||||||
tags:
|
tags:
|
||||||
- docker_host
|
- docker_host
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
---
|
---
|
||||||
- name: Set up reverse proxy for docker
|
- name: Set up reverse proxy for docker
|
||||||
hosts: docker_lb
|
hosts: docker
|
||||||
gather_facts: yes
|
gather_facts: true
|
||||||
vars_files:
|
|
||||||
- secrets.yml
|
|
||||||
roles:
|
roles:
|
||||||
- role: common
|
- role: common
|
||||||
tags:
|
tags:
|
||||||
- common
|
- common
|
||||||
|
when: inventory_hostname in groups["docker_lb"]
|
||||||
- role: reverse_proxy
|
- role: reverse_proxy
|
||||||
tags:
|
tags:
|
||||||
- reverse_proxy
|
- reverse_proxy
|
||||||
|
when: inventory_hostname in groups["docker_lb"]
|
||||||
5
playbooks/docker.yaml
Normal file
5
playbooks/docker.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- name: Setup Docker Hosts
|
||||||
|
ansible.builtin.import_playbook: docker-host.yaml
|
||||||
|
- name: Setup Docker load balancer
|
||||||
|
ansible.builtin.import_playbook: docker-lb.yaml
|
||||||
16
playbooks/k3s-agents.yaml
Normal file
16
playbooks/k3s-agents.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
- 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
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
- 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
|
|
||||||
17
playbooks/k3s-loadbalancer.yaml
Normal file
17
playbooks/k3s-loadbalancer.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
- 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"]
|
||||||
17
playbooks/k3s-servers.yaml
Normal file
17
playbooks/k3s-servers.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
- 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"]
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
- 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
|
|
||||||
16
playbooks/k3s-storage.yaml
Normal file
16
playbooks/k3s-storage.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
- 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
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
- 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
|
|
||||||
10
playbooks/kubernetes_setup.yaml
Normal file
10
playbooks/kubernetes_setup.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
- 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
|
|
||||||
6
playbooks/proxmox-k3s-add-agent.yaml
Normal file
6
playbooks/proxmox-k3s-add-agent.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: Create new VM(s)
|
||||||
|
ansible.builtin.import_playbook: proxmox.yaml
|
||||||
|
|
||||||
|
- name: Provision VM
|
||||||
|
ansible.builtin.import_playbook: k3s-agents.yaml
|
||||||
15
playbooks/proxmox.yaml
Normal file
15
playbooks/proxmox.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
- hosts: db
|
|
||||||
gather_facts: yes
|
|
||||||
vars_files:
|
|
||||||
- secrets.yml
|
|
||||||
tasks:
|
|
||||||
- name: Print the database connection string
|
|
||||||
debug:
|
|
||||||
msg: "{{ k3s_db_connection_string }}"
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
- name: Provision Local Ubuntu Machine
|
|
||||||
hosts: local
|
|
||||||
gather_facts: true
|
|
||||||
roles:
|
|
||||||
- ubuntu
|
|
||||||
28
requirements.txt
Normal file
28
requirements.txt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
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
|
||||||
5
requirements.yaml
Normal file
5
requirements.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
collections:
|
||||||
|
- name: community.docker
|
||||||
|
- name: community.general
|
||||||
|
- name: kubernetes.core
|
||||||
72
roles/common/README.md
Normal file
72
roles/common/README.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# 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/).
|
||||||
80
roles/common/files/ghostty/infocmp
Normal file
80
roles/common/files/ghostty/infocmp
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
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\\,
|
||||||
18
roles/common/files/ssh/root/sshd_config
Normal file
18
roles/common/files/ssh/root/sshd_config
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
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,4 +1,3 @@
|
|||||||
Include /etc/ssh/sshd_config.d/*.conf
|
|
||||||
Protocol 2
|
Protocol 2
|
||||||
PermitRootLogin no
|
PermitRootLogin no
|
||||||
MaxAuthTries 3
|
MaxAuthTries 3
|
||||||
@@ -13,6 +12,7 @@ X11Forwarding no
|
|||||||
PrintMotd no
|
PrintMotd no
|
||||||
TCPKeepAlive no
|
TCPKeepAlive no
|
||||||
ClientAliveCountMax 2
|
ClientAliveCountMax 2
|
||||||
|
TrustedUserCAKeys /etc/ssh/vault-ca.pub
|
||||||
UseDNS yes
|
UseDNS yes
|
||||||
AcceptEnv LANG LC_*
|
AcceptEnv LANG LC_*
|
||||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||||
1
roles/common/files/ssh/vault-ca.pub
Normal file
1
roles/common/files/ssh/vault-ca.pub
Normal file
@@ -0,0 +1 @@
|
|||||||
|
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:
|
service:
|
||||||
name: sshd
|
name: sshd
|
||||||
state: restarted
|
state: restarted
|
||||||
become: yes
|
become: true
|
||||||
24
roles/common/tasks/bash.yaml
Normal file
24
roles/common/tasks/bash.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
- 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,7 +11,6 @@
|
|||||||
url: https://raw.githubusercontent.com/eza-community/eza/main/deb.asc
|
url: https://raw.githubusercontent.com/eza-community/eza/main/deb.asc
|
||||||
dest: /etc/apt/keyrings/gierens.asc
|
dest: /etc/apt/keyrings/gierens.asc
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
register: gpg_key_result
|
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
- name: Add Gierens repository to apt sources
|
- name: Add Gierens repository to apt sources
|
||||||
@@ -80,12 +79,13 @@
|
|||||||
path: ~/.config/nvim
|
path: ~/.config/nvim
|
||||||
register: nvim_config
|
register: nvim_config
|
||||||
|
|
||||||
- name: Clone LazyVim starter to Neovim config directory
|
- name: Clone personal Neovim config directory
|
||||||
ansible.builtin.git:
|
ansible.builtin.git:
|
||||||
repo: https://github.com/LazyVim/starter
|
repo: https://codeberg.org/tudattr/nvim
|
||||||
dest: ~/.config/nvim
|
dest: ~/.config/nvim
|
||||||
clone: true
|
clone: true
|
||||||
update: false
|
update: false
|
||||||
|
version: 1.0.0
|
||||||
when: not nvim_config.stat.exists
|
when: not nvim_config.stat.exists
|
||||||
|
|
||||||
- name: Remove .git directory from Neovim config
|
- name: Remove .git directory from Neovim config
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
---
|
---
|
||||||
- name: Set a hostname
|
- name: Set a hostname
|
||||||
ansible.builtin.hostname:
|
ansible.builtin.hostname:
|
||||||
name: "{{ host.hostname }}"
|
name: "{{ inventory_hostname }}"
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
- name: Update /etc/hosts to reflect the new hostname
|
- name: Update /etc/hosts to reflect the new hostname
|
||||||
ansible.builtin.lineinfile:
|
ansible.builtin.lineinfile:
|
||||||
path: /etc/hosts
|
path: /etc/hosts
|
||||||
regexp: '^127\.0\.1\.1'
|
regexp: '^127\.0\.1\.1'
|
||||||
line: "127.0.1.1 {{ host.hostname }}"
|
line: "127.0.1.1 {{ inventory_hostname }}"
|
||||||
state: present
|
state: present
|
||||||
backup: true
|
backup: true
|
||||||
become: true
|
become: true
|
||||||
13
roles/common/tasks/main.yaml
Normal file
13
roles/common/tasks/main.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
- 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
|
|
||||||
28
roles/common/tasks/packages.yaml
Normal file
28
roles/common/tasks/packages.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
- 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"
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
- 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
|
|
||||||
28
roles/common/tasks/sshd.yaml
Normal file
28
roles/common/tasks/sshd.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
- 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"
|
|
||||||
11
roles/common/tasks/time.yaml
Normal file
11
roles/common/tasks/time.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- 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"
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Set timezone to "{{ timezone }}"
|
|
||||||
community.general.timezone:
|
|
||||||
name: "{{ timezone }}"
|
|
||||||
18
roles/common/vars/main.yaml
Normal file
18
roles/common/vars/main.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
common_packages:
|
||||||
|
- build-essential
|
||||||
|
- curl
|
||||||
|
- git
|
||||||
|
- iperf3
|
||||||
|
- neovim
|
||||||
|
- rsync
|
||||||
|
- smartmontools
|
||||||
|
- sudo
|
||||||
|
- systemd-timesyncd
|
||||||
|
- tree
|
||||||
|
- screen
|
||||||
|
- bat
|
||||||
|
- fd-find
|
||||||
|
- ripgrep
|
||||||
|
- nfs-common
|
||||||
|
- open-iscsi
|
||||||
|
- parted
|
||||||
85
roles/docker_host/README.md
Normal file
85
roles/docker_host/README.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# 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,4 +8,14 @@
|
|||||||
- name: Restart compose
|
- name: Restart compose
|
||||||
community.docker.docker_compose_v2:
|
community.docker.docker_compose_v2:
|
||||||
project_src: "{{ docker.directories.compose }}"
|
project_src: "{{ docker.directories.compose }}"
|
||||||
state: restarted
|
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
|
||||||
50
roles/docker_host/tasks/10_setup.yaml
Normal file
50
roles/docker_host/tasks/10_setup.yaml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
- curl
|
- curl
|
||||||
- gnupg
|
- gnupg
|
||||||
- lsb-release
|
- lsb-release
|
||||||
|
- qemu-guest-agent
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
- name: Add Docker apt key.
|
- name: Add Docker apt key.
|
||||||
@@ -5,10 +5,12 @@
|
|||||||
state: present
|
state: present
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
- name: Append the group docker to "{{ user }}"
|
- name: Append the group docker to "{{ ansible_user_id }}"
|
||||||
ansible.builtin.user:
|
ansible.builtin.user:
|
||||||
name: "{{ user }}"
|
name: "{{ ansible_user_id }}"
|
||||||
shell: /bin/bash
|
shell: /bin/bash
|
||||||
groups: docker
|
groups: docker
|
||||||
append: true
|
append: true
|
||||||
become: true
|
become: true
|
||||||
|
notify:
|
||||||
|
- Restart host
|
||||||
@@ -5,23 +5,23 @@
|
|||||||
state: directory
|
state: directory
|
||||||
mode: "0755"
|
mode: "0755"
|
||||||
loop:
|
loop:
|
||||||
- /media/docker
|
|
||||||
- /media/series
|
- /media/series
|
||||||
- /media/movies
|
- /media/movies
|
||||||
- /media/songs
|
- /media/songs
|
||||||
- "{{ docker.directories.opt }}"
|
- "{{ docker.directories.local }}"
|
||||||
|
- "{{ docker.directories.config }}"
|
||||||
- "{{ docker.directories.compose }}"
|
- "{{ docker.directories.compose }}"
|
||||||
- /opt/local
|
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
- name: Set ownership to {{ user }}
|
- name: Set ownership to {{ ansible_user_id }}
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ item }}"
|
path: "{{ item }}"
|
||||||
owner: "{{ user }}"
|
owner: "{{ ansible_user_id }}"
|
||||||
group: "{{ user }}"
|
group: "{{ ansible_user_id }}"
|
||||||
loop:
|
loop:
|
||||||
- "{{ docker.directories.opt }}"
|
- "{{ docker.directories.local }}"
|
||||||
- /opt/local
|
- "{{ docker.directories.config }}"
|
||||||
|
- "{{ docker.directories.compose }}"
|
||||||
- /media
|
- /media
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
@@ -37,4 +37,5 @@
|
|||||||
- /media/series
|
- /media/series
|
||||||
- /media/movies
|
- /media/movies
|
||||||
- /media/songs
|
- /media/songs
|
||||||
|
- /media/downloads
|
||||||
become: true
|
become: true
|
||||||
31
roles/docker_host/tasks/50_provision.yaml
Normal file
31
roles/docker_host/tasks/50_provision.yaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
- 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:
|
ansible.builtin.template:
|
||||||
src: "templates/compose.yaml.j2"
|
src: "templates/compose.yaml.j2"
|
||||||
dest: "{{ docker.directories.compose }}/compose.yaml"
|
dest: "{{ docker.directories.compose }}/compose.yaml"
|
||||||
owner: "{{ user }}"
|
owner: "{{ ansible_user_id }}"
|
||||||
group: "{{ user }}"
|
group: "{{ ansible_user_id }}"
|
||||||
mode: "644"
|
mode: "644"
|
||||||
backup: true
|
backup: true
|
||||||
notify:
|
notify:
|
||||||
21
roles/docker_host/tasks/main.yaml
Normal file
21
roles/docker_host/tasks/main.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
- 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
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Enable HW accelerate for VM
|
|
||||||
ansible.builtin.apt:
|
|
||||||
name: "{{ item }}"
|
|
||||||
state: present
|
|
||||||
loop:
|
|
||||||
- firmware-misc-nonfree
|
|
||||||
- nfs-common
|
|
||||||
become: true
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
services:
|
services:
|
||||||
{% for service in services %}
|
{% for service in services %}
|
||||||
{% if inventory_hostname in service.vm %}
|
{% if inventory_hostname in service.vm %}
|
||||||
|
|
||||||
{{ service.name }}:
|
{{ service.name }}:
|
||||||
container_name: {{ service.container_name }}
|
container_name: {{ service.container_name }}
|
||||||
image: {{ service.image }}
|
image: {{ service.image }}
|
||||||
restart: {{ service.restart }}
|
restart: unless-stopped
|
||||||
{% if service.network_mode is not defined %}
|
{% if service.network_mode is not defined %}
|
||||||
hostname: {{ service.name }}
|
hostname: {{ service.name }}
|
||||||
networks:
|
networks:
|
||||||
@@ -20,6 +21,35 @@ services:
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% 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 %}
|
{% if service.cap_add is defined and service.cap_add is iterable %}
|
||||||
cap_add:
|
cap_add:
|
||||||
{% for cap in service.cap_add %}
|
{% for cap in service.cap_add %}
|
||||||
@@ -56,31 +86,73 @@ services:
|
|||||||
- {{ device.external }}:{{ device.internal }}
|
- {{ device.external }}:{{ device.internal }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if service.name == 'paperless' %}
|
{% if service.command is defined and service.command is iterable %}
|
||||||
|
command:
|
||||||
{{service.name}}-broker:
|
{% for command in service.command %}
|
||||||
container_name: paperless-broker
|
- {{ command }}
|
||||||
image: docker.io/library/redis:7
|
{% endfor %}
|
||||||
restart: unless-stopped
|
{% endif %}
|
||||||
networks:
|
{% if service.sub_service is defined and service.sub_service is iterable %}
|
||||||
- net
|
{% for sub in service.sub_service %}
|
||||||
volumes:
|
{% if sub.name is defined and sub.name == "postgres" %}
|
||||||
- /opt/local/paperless/redis/data:/data
|
{{ service.name }}-postgres:
|
||||||
|
container_name: {{ service.name }}-postgres
|
||||||
{{service.name}}-postgres:
|
image: docker.io/library/postgres:{{ sub.version }}
|
||||||
container_name: paperless-postgres
|
restart: unless-stopped
|
||||||
image: docker.io/library/postgres:15
|
hostname: {{ service.name }}-postgres
|
||||||
restart: unless-stopped
|
networks:
|
||||||
networks:
|
- net
|
||||||
- net
|
volumes:
|
||||||
volumes:
|
- /opt/local/{{ service.name }}/postgres/data:/var/lib/postgresql/data
|
||||||
- /opt/local/paperless/db/data:/var/lib/postgresql/data
|
environment:
|
||||||
environment:
|
POSTGRES_DB: {{ service.name }}
|
||||||
POSTGRES_DB: paperless
|
POSTGRES_USER: {{ sub.username }}
|
||||||
POSTGRES_USER: paperless
|
POSTGRES_PASSWORD: {{ sub.password }}
|
||||||
POSTGRES_PASSWORD: 5fnhn%u2YWY3paNvMAjdoufYPQ2Hf3Yi
|
{% 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 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
networks:
|
networks:
|
||||||
@@ -90,6 +162,3 @@ networks:
|
|||||||
driver: default
|
driver: default
|
||||||
config:
|
config:
|
||||||
- subnet: 172.16.69.0/24
|
- subnet: 172.16.69.0/24
|
||||||
|
|
||||||
volumes:
|
|
||||||
prometheus_data: {}
|
|
||||||
|
|||||||
79
roles/docker_host/templates/keycloak/realm.json.j2
Normal file
79
roles/docker_host/templates/keycloak/realm.json.j2
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"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 %}
|
||||||
|
]
|
||||||
|
}
|
||||||
7
roles/docker_host/vars/main.yaml
Normal file
7
roles/docker_host/vars/main.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
docker_host_package_common_dependencies:
|
||||||
|
- nfs-common
|
||||||
|
|
||||||
|
apt_lock_files:
|
||||||
|
- /var/lib/dpkg/lock
|
||||||
|
- /var/lib/dpkg/lock-frontend
|
||||||
|
- /var/cache/apt/archives/lock
|
||||||
75
roles/edge_vps/README.md
Normal file
75
roles/edge_vps/README.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# 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
|
||||||
11
roles/edge_vps/defaults/main.yaml
Normal file
11
roles/edge_vps/defaults/main.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
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
|
||||||
20
roles/edge_vps/files/elastic-agent/elasticsearch-ca.crt
Normal file
20
roles/edge_vps/files/elastic-agent/elasticsearch-ca.crt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
-----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-----
|
||||||
20
roles/edge_vps/files/elastic-agent/fleet-ca.crt
Normal file
20
roles/edge_vps/files/elastic-agent/fleet-ca.crt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
-----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-----
|
||||||
12
roles/edge_vps/handlers/main.yaml
Normal file
12
roles/edge_vps/handlers/main.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
30
roles/edge_vps/tasks/10_directories.yaml
Normal file
30
roles/edge_vps/tasks/10_directories.yaml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
- 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 }}"
|
||||||
19
roles/edge_vps/tasks/20_wireguard.yaml
Normal file
19
roles/edge_vps/tasks/20_wireguard.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
15
roles/edge_vps/tasks/30_traefik.yaml
Normal file
15
roles/edge_vps/tasks/30_traefik.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
24
roles/edge_vps/tasks/40_pangolin.yaml
Normal file
24
roles/edge_vps/tasks/40_pangolin.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
29
roles/edge_vps/tasks/50_elastic_agent.yaml
Normal file
29
roles/edge_vps/tasks/50_elastic_agent.yaml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
- 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
|
||||||
15
roles/edge_vps/tasks/main.yaml
Normal file
15
roles/edge_vps/tasks/main.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- name: Setup directories
|
||||||
|
ansible.builtin.include_tasks: 10_directories.yaml
|
||||||
|
|
||||||
|
- name: Setup WireGuard
|
||||||
|
ansible.builtin.include_tasks: 20_wireguard.yaml
|
||||||
|
|
||||||
|
- name: Setup Traefik
|
||||||
|
ansible.builtin.include_tasks: 30_traefik.yaml
|
||||||
|
|
||||||
|
- name: Setup Pangolin
|
||||||
|
ansible.builtin.include_tasks: 40_pangolin.yaml
|
||||||
|
|
||||||
|
- name: Setup Elastic Agent
|
||||||
|
ansible.builtin.include_tasks: 50_elastic_agent.yaml
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user