From 56f058c2546ae8cf10fce1af6ed52854bc79ef0e Mon Sep 17 00:00:00 2001 From: Tuan-Dat Tran Date: Tue, 25 Mar 2025 01:09:08 +0100 Subject: [PATCH 1/8] moved ssh to cert based Signed-off-by: Tuan-Dat Tran --- ansible.cfg | 5 +- group_vars/all/secrets.yml | 117 +++++++++++---------- group_vars/docker/vars.yml | 6 +- group_vars/proxmox/vars.yml | 13 +++ host_vars/docker-host00.yml | 11 +- host_vars/docker-host01.yml | 11 +- host_vars/docker-host02.yml | 11 +- host_vars/docker-lb.yml | 10 +- playbooks/docker-host.yml | 2 +- playbooks/docker-lb.yml | 2 +- playbooks/docker.yml | 5 + playbooks/proxmox.yml | 10 ++ inventory/production => production.ini | 3 + requirements.txt | 6 ++ roles/common/files/ssh/vault-ca.pub | 1 + roles/common/tasks/sshd.yml | 7 +- roles/common/templates/ssh/sshd_config | 2 +- roles/proxmox_vm/tasks/create_vm.yml | 7 ++ roles/proxmox_vm/tasks/get_info.yml | 11 ++ roles/proxmox_vm/tasks/main.yml | 5 + roles/reverse_proxy/templates/Caddyfile.j2 | 2 +- 21 files changed, 160 insertions(+), 87 deletions(-) create mode 100644 group_vars/proxmox/vars.yml create mode 100644 playbooks/docker.yml create mode 100644 playbooks/proxmox.yml rename inventory/production => production.ini (92%) create mode 100644 requirements.txt create mode 100644 roles/common/files/ssh/vault-ca.pub create mode 100644 roles/proxmox_vm/tasks/create_vm.yml create mode 100644 roles/proxmox_vm/tasks/get_info.yml create mode 100644 roles/proxmox_vm/tasks/main.yml diff --git a/ansible.cfg b/ansible.cfg index 7dad879..3d7a459 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -1,9 +1,12 @@ [defaults] +# (string) Path to the Python interpreter to be used for module execution on remote targets, or an automatic discovery mode. Supported discovery modes are ``auto`` (the default), ``auto_silent``, ``auto_legacy``, and ``auto_legacy_silent``. All discovery modes employ a lookup table to use the included system Python (on distributions known to include one), falling back to a fixed ordered list of well-known Python interpreter locations if a platform-specific default is not available. The fallback behavior will issue a warning that the interpreter should be set explicitly (since interpreters installed later may change which one is used). This warning behavior can be disabled by setting ``auto_silent`` or ``auto_legacy_silent``. The value of ``auto_legacy`` provides all the same behavior, but for backwards-compatibility with older Ansible releases that always defaulted to ``/usr/bin/python``, will use that interpreter if present. +interpreter_python=python3 + # (pathspec) Colon separated paths in which Ansible will search for Roles. roles_path=./roles # (pathlist) Comma separated list of Ansible inventory sources -inventory=./inventory/production +inventory=./production.ini # (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. diff --git a/group_vars/all/secrets.yml b/group_vars/all/secrets.yml index 5c78dc6..7a8a6e3 100644 --- a/group_vars/all/secrets.yml +++ b/group_vars/all/secrets.yml @@ -1,56 +1,63 @@ $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 +62353334666233376566326532636437376331316231323234643438323138316538363739343966 +3637633035343637363766613038346162336437303035390a663363313565343230346363646534 +39393835313839323534663430646461336536343764636463376262646666356465386234313635 +3965343062616437660a613633343839303638656464616638306234363732656139653736373262 +63643739313466353637613738343233353738373764653762343432643430383637313137376236 +37643033323439656161333361346638643562393031363230383033363862316162353132313161 +61323433643933323735376163666564666264666461666234376664323661333734313231623730 +65323839383932303436306434356334396130353236323965646564303930383765376265356438 +35633031623036313634333534663564653863366535643466306332386166666531343262386330 +32633530313666653462326565643163616632333835643231643063393438356265313638336662 +36376132353931613835343030633464633561613361376264613535383830376337303539316133 +64666164306235333663303564656364303762326262313835343233303465653934623965653933 +62336130653938643966656665306134376237376537663533306261623132653838363034626131 +39346339666566633037663730313732393464306438623630326533333866636465353631373435 +61623833393039393961633664383939623930633562383936373036616431333664376364663930 +36326666653431326332316361336439303163643061343435643363376665616135653036663466 +65613563356631633238303731366330303265396661303735616534653731616439613531353939 +35386562626432616239643665663432373536623064383963306537386338636437663439313066 +64373336373830633163633433666334393035336539363261336364376139373434316433643364 +35353035326134626661663730383132323466343938373562336332663964393164663731633231 +37386330363531616566663965613164663463303762363635323438366130336334323134393332 +37313638346162633561393562666334616464303330376230633264623262336335613063653665 +32393332396631363562643961336166666339326233366364333061303766616632323732666338 +39363864336634356535333063343730663231303839393061366238353032643965353939656135 +39316539333338333431383635323537653761356665343136303231633265643735623962346133 +66313132313765643231373435653266633564316331633563623138303835616133303061333239 +39333362323162303466383865343031663663613266643932653862623137663766343665366263 +66303962353330653162356333343231393137613763316134663135613738666231373835616563 +33656564343864333263646437656435363338376663636435353432643931303032306330353831 +37623634353735373635303934653034356431346330376637656435356530656131343736636463 +63376565333730623335386231333838353763633031663238346438643664373130343632313462 +39343033623939653865383965653331366539643934363236663631313537323338643266313030 +65363736653237336633343333393665333666386336666630366664313336393136383734613635 +62366365356262643632306430626166346636343837653730626665646631373966396535666336 +36396464626437393433656361386263613330333561643563643232333064333565626534353736 +32653239353531343265353631623430363537396233363666393335356261323532633432376139 +33663266303631383936623332313833616262616635356139336165323662656131643334633563 +39396538383661306564333239383131623039303835323636326532653331346135343065363533 +32616533643662643365383132666438383237396362653465666264346333383133653738643166 +61393561396535343230343665363235326561666565376165323262396638626631363032643865 +66656439626339653837353133626133326234333036386563353532383764613261326130363361 +39663233656538356334326530366132346339666161386433393431663262646433353430366532 +31336661316562323534356632616633363862366163346532613433393434323639313733656562 +37633962613630336661623733626237613365623436346662376135646563353735623030303064 +34303064323635306465326638633665333639306564343034646262326466323539643437646239 +65343865646137336564356438623739323639336437626564393337343232313563353762333561 +65633265386132666635303831653236346165623537343638326639383436326633323163643765 +63336439643465313039653362373538333834666432383533376233643031323665303161336630 +34643462376262363530633933393631343662393631356338316538333366303966623936633163 +31643663616536626538323033396564656432373938383637373831306432353034383630323133 +66646339636335623835636638653533323365323132383134636264396465393463353234363839 +62323236386235303830393930346632366331653632306633376335643232633432386536663630 +35393035303162666563653137613639636561396666623665323832636364336232333165336135 +36626465393762373064353561333939626638613335323066666366326539316438363736373331 +64303538663863613135303531326465666636386364356635316265373533366434323330323266 +39613464343138616235663035316538636137396532373365393866376666343631626333306436 +66383734303032343131356466333264393739663834393836376236656634373832356363343639 +61306436366665616438636539386363616166633536316533386332383632366265313161643965 +31386463323438336165383764396166393530623537666662353735646535653938383031333331 +32646431366166373264326564326630313634333639646662376165643861616139336231373432 +30666165373861343965333264303632623766633763376339353366313839336537616131616436 +6236303866623939313466633635633136383232363034376236 diff --git a/group_vars/docker/vars.yml b/group_vars/docker/vars.yml index 522b0a3..00ea96a 100644 --- a/group_vars/docker/vars.yml +++ b/group_vars/docker/vars.yml @@ -111,7 +111,7 @@ services: - VERSION=docker - name: jellyfin vm: - - docker-host02 + - docker-host01 container_name: jellyfin image: jellyfin/jellyfin restart: "unless-stopped" @@ -142,7 +142,7 @@ services: environment: - name: hass vm: - - docker-host02 + - docker-host01 container_name: homeassistant image: "ghcr.io/home-assistant/home-assistant:stable" restart: unless-stopped @@ -319,7 +319,7 @@ services: external: 8080 - name: git vm: - - docker-host02 + - docker-host01 container_name: gitea image: gitea/gitea:1.23.1-rootless restart: unless-stopped diff --git a/group_vars/proxmox/vars.yml b/group_vars/proxmox/vars.yml new file mode 100644 index 0000000..d3329f5 --- /dev/null +++ b/group_vars/proxmox/vars.yml @@ -0,0 +1,13 @@ +proxmox_api_user: root +proxmox_api_host: 192.168.20.12 +proxmox_api_password: "{{ vault.pve.aya01.root.sudo }}" + +proxmox_vms: + - name: "test-vm-00" + hostname: "test-vm-00" + node: + - "aya01" + ostemplate: "" + +proxmox_lxcs: + - name: "test-lxc-00" diff --git a/host_vars/docker-host00.yml b/host_vars/docker-host00.yml index 154dc19..74135f1 100644 --- a/host_vars/docker-host00.yml +++ b/host_vars/docker-host00.yml @@ -1,10 +1,11 @@ --- -ansible_user: "{{ user }}" -ansible_host: 192.168.20.34 -ansible_port: 22 -ansible_ssh_private_key_file: "{{ pk_path }}" +# Configure this in ~/.ssh/config* +# 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 }}" + ip: "192.168.20.34" diff --git a/host_vars/docker-host01.yml b/host_vars/docker-host01.yml index a493c5e..19c5d36 100644 --- a/host_vars/docker-host01.yml +++ b/host_vars/docker-host01.yml @@ -1,10 +1,11 @@ --- -ansible_user: "{{ user }}" -ansible_host: 192.168.20.35 -ansible_port: 22 -ansible_ssh_private_key_file: "{{ pk_path }}" +# Configure this in ~/.ssh/config* +# 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 }}" + ip: "192.168.20.35" diff --git a/host_vars/docker-host02.yml b/host_vars/docker-host02.yml index 9debe14..589ac16 100644 --- a/host_vars/docker-host02.yml +++ b/host_vars/docker-host02.yml @@ -1,10 +1,11 @@ --- -ansible_user: "{{ user }}" -ansible_host: 192.168.20.36 -ansible_port: 22 -ansible_ssh_private_key_file: "{{ pk_path }}" +# Configure this in ~/.ssh/config* +# 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 }}" + ip: "192.168.20.36" diff --git a/host_vars/docker-lb.yml b/host_vars/docker-lb.yml index ab2b1ad..7024e36 100644 --- a/host_vars/docker-lb.yml +++ b/host_vars/docker-lb.yml @@ -1,10 +1,10 @@ --- -ansible_user: "{{ user }}" -ansible_host: 192.168.20.37 -ansible_port: 22 -ansible_ssh_private_key_file: "{{ pk_path }}" +# 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 }}" + ip: "192.168.20.37" diff --git a/playbooks/docker-host.yml b/playbooks/docker-host.yml index 01324e3..199fc11 100644 --- a/playbooks/docker-host.yml +++ b/playbooks/docker-host.yml @@ -1,7 +1,7 @@ --- - name: Set up Servers hosts: docker_host - gather_facts: yes + gather_facts: true vars_files: - secrets.yml roles: diff --git a/playbooks/docker-lb.yml b/playbooks/docker-lb.yml index 97995e5..150dec0 100644 --- a/playbooks/docker-lb.yml +++ b/playbooks/docker-lb.yml @@ -1,7 +1,7 @@ --- - name: Set up reverse proxy for docker hosts: docker_lb - gather_facts: yes + gather_facts: true vars_files: - secrets.yml roles: diff --git a/playbooks/docker.yml b/playbooks/docker.yml new file mode 100644 index 0000000..3065b90 --- /dev/null +++ b/playbooks/docker.yml @@ -0,0 +1,5 @@ +--- +- name: Setup Docker Hosts + ansible.builtin.import_playbook: docker-host.yml +- name: Setup Docker load balancer + ansible.builtin.import_playbook: docker-lb.yml diff --git a/playbooks/proxmox.yml b/playbooks/proxmox.yml new file mode 100644 index 0000000..7706349 --- /dev/null +++ b/playbooks/proxmox.yml @@ -0,0 +1,10 @@ +--- +- name: Run proxmox vm playbook + hosts: proxmox + gather_facts: true + vars_files: + - secrets.yml + roles: + - role: proxmox_vm + tags: + - proxmox_vm diff --git a/inventory/production b/production.ini similarity index 92% rename from inventory/production rename to production.ini index ad976af..183cf78 100644 --- a/inventory/production +++ b/production.ini @@ -1,4 +1,7 @@ [proxmox] +127.0.0.1 ansible_connection=local + +[proxmox:children] aya01 lulu inko diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0d1b6c4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +certifi==2025.1.31 +charset-normalizer==3.4.1 +idna==3.10 +proxmoxer==2.2.0 +requests==2.32.3 +urllib3==2.3.0 diff --git a/roles/common/files/ssh/vault-ca.pub b/roles/common/files/ssh/vault-ca.pub new file mode 100644 index 0000000..413aef3 --- /dev/null +++ b/roles/common/files/ssh/vault-ca.pub @@ -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== diff --git a/roles/common/tasks/sshd.yml b/roles/common/tasks/sshd.yml index ff28064..b102abf 100644 --- a/roles/common/tasks/sshd.yml +++ b/roles/common/tasks/sshd.yml @@ -10,8 +10,7 @@ - name: Copy pubkey ansible.builtin.copy: - content: "{{ pubkey }}" - dest: "/home/{{ user }}/.ssh/authorized_keys" - owner: "{{ user }}" - group: "{{ user }}" + src: files/ssh/vault-ca.pub + dest: "/etc/ssh/vault-ca.pub" mode: "644" + become: true diff --git a/roles/common/templates/ssh/sshd_config b/roles/common/templates/ssh/sshd_config index 172784e..fa02962 100644 --- a/roles/common/templates/ssh/sshd_config +++ b/roles/common/templates/ssh/sshd_config @@ -1,4 +1,3 @@ -Include /etc/ssh/sshd_config.d/*.conf Protocol 2 PermitRootLogin no MaxAuthTries 3 @@ -13,6 +12,7 @@ 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 diff --git a/roles/proxmox_vm/tasks/create_vm.yml b/roles/proxmox_vm/tasks/create_vm.yml new file mode 100644 index 0000000..32cd4d1 --- /dev/null +++ b/roles/proxmox_vm/tasks/create_vm.yml @@ -0,0 +1,7 @@ +--- +# - name: Create VM +# community.general.proxmox: +# api_host: "{{ api_host }}" +# api_user: "{{ api_user }}" +# api_password: "{{ vault.proxmox.api_password }}" +# node: "{{ }}" diff --git a/roles/proxmox_vm/tasks/get_info.yml b/roles/proxmox_vm/tasks/get_info.yml new file mode 100644 index 0000000..d1670e0 --- /dev/null +++ b/roles/proxmox_vm/tasks/get_info.yml @@ -0,0 +1,11 @@ +--- +- name: List existing nodes + community.general.proxmox_node_info: + api_host: "{{ proxmox_api_host }}" + api_user: "{{ proxmox_api_user }}@pam" + api_password: "{{ proxmox_api_password }}" + register: proxmox_nodes + +- name: Print info + ansible.builtin.debug: + msg: "{{ proxmox_nodes }}" diff --git a/roles/proxmox_vm/tasks/main.yml b/roles/proxmox_vm/tasks/main.yml new file mode 100644 index 0000000..8932427 --- /dev/null +++ b/roles/proxmox_vm/tasks/main.yml @@ -0,0 +1,5 @@ +--- +- name: Get info + ansible.builtin.include_tasks: get_info.yml +# - name: Create vm +# ansible.builtin.include_tasks: create_vm.yml diff --git a/roles/reverse_proxy/templates/Caddyfile.j2 b/roles/reverse_proxy/templates/Caddyfile.j2 index 0af73e0..389859c 100644 --- a/roles/reverse_proxy/templates/Caddyfile.j2 +++ b/roles/reverse_proxy/templates/Caddyfile.j2 @@ -10,7 +10,7 @@ {% if http_port %} {{ service.name }}.{{ domain }} { {% for vm in service.vm %} - reverse_proxy {{ hostvars[vm].ansible_host }}:{{ http_port[0] }} + reverse_proxy {{ hostvars[vm].host.ip }}:{{ http_port[0] }} {% endfor %} log { output file /var/log/caddy/{{ service.name }}.log -- 2.49.1 From 27621aac0394b84a5e6e1c214a7e38aa8a52b906 Mon Sep 17 00:00:00 2001 From: Tuan-Dat Tran Date: Sun, 6 Apr 2025 18:04:33 +0200 Subject: [PATCH 2/8] Added proxmox-vm and static tagging of docker images Signed-off-by: Tuan-Dat Tran --- group_vars/docker/vars.yml | 207 ++++++++++--------- group_vars/proxmox/secrets_vm.yml | 8 + group_vars/proxmox/vars.yml | 17 +- playbooks/proxmox.yml | 6 +- production.ini | 6 +- roles/docker_host/handlers/main.yml | 6 +- roles/proxmox/files/check_proxmox_vm.sh | 83 ++++++++ roles/proxmox/tasks/01_setup_user.yml | 0 roles/proxmox/tasks/10_create_secrets.yml | 33 +++ roles/proxmox/tasks/15_create_secret.yml | 26 +++ roles/proxmox/tasks/50_create_vms.yml | 11 + roles/proxmox/tasks/55_create_vm.yml | 34 +++ roles/proxmox/tasks/60_create_container.yml | 11 + roles/proxmox/tasks/65_create_containers.yml | 4 + roles/proxmox/tasks/90-download-image.yml | 6 + roles/proxmox/tasks/main.yml | 12 ++ roles/proxmox/vars/main.yml | 10 + roles/proxmox_vm/tasks/create_vm.yml | 7 - roles/proxmox_vm/tasks/get_info.yml | 11 - roles/proxmox_vm/tasks/main.yml | 5 - 20 files changed, 377 insertions(+), 126 deletions(-) create mode 100644 group_vars/proxmox/secrets_vm.yml create mode 100755 roles/proxmox/files/check_proxmox_vm.sh create mode 100644 roles/proxmox/tasks/01_setup_user.yml create mode 100644 roles/proxmox/tasks/10_create_secrets.yml create mode 100644 roles/proxmox/tasks/15_create_secret.yml create mode 100644 roles/proxmox/tasks/50_create_vms.yml create mode 100644 roles/proxmox/tasks/55_create_vm.yml create mode 100644 roles/proxmox/tasks/60_create_container.yml create mode 100644 roles/proxmox/tasks/65_create_containers.yml create mode 100644 roles/proxmox/tasks/90-download-image.yml create mode 100644 roles/proxmox/tasks/main.yml create mode 100644 roles/proxmox/vars/main.yml delete mode 100644 roles/proxmox_vm/tasks/create_vm.yml delete mode 100644 roles/proxmox_vm/tasks/get_info.yml delete mode 100644 roles/proxmox_vm/tasks/main.yml diff --git a/group_vars/docker/vars.yml b/group_vars/docker/vars.yml index 00ea96a..b6e6938 100644 --- a/group_vars/docker/vars.yml +++ b/group_vars/docker/vars.yml @@ -15,7 +15,7 @@ services: vm: - docker-host00 container_name: syncthing - image: syncthing/syncthing + image: syncthing/syncthing:1.29 restart: unless-stopped volumes: - name: "Data" @@ -42,7 +42,7 @@ services: vm: - docker-host00 container_name: kuma - image: louislam/uptime-kuma:1 + image: louislam/uptime-kuma:1.23.16 restart: unless-stopped volumes: - name: "Data" @@ -60,7 +60,7 @@ services: vm: - docker-host00 container_name: plex - image: lscr.io/linuxserver/plex:latest + image: lscr.io/linuxserver/plex:1.41.5 restart: unless-stopped volumes: - name: "Configuration" @@ -113,7 +113,7 @@ services: vm: - docker-host01 container_name: jellyfin - image: jellyfin/jellyfin + image: jellyfin/jellyfin:10.10 restart: "unless-stopped" volumes: - name: "Configuration" @@ -171,7 +171,7 @@ services: vm: - docker-host00 container_name: ddns-updater - image: ghcr.io/qdm12/ddns-updater + image: qmcgaw/ddns-updater:2 restart: unless-stopped volumes: - name: "Configuration" @@ -185,7 +185,7 @@ services: vm: - docker-host00 container_name: sonarr - image: lscr.io/linuxserver/sonarr:latest + image: linuxserver/sonarr:4.0.14 restart: unless-stopped volumes: - name: "Configuration" @@ -209,7 +209,7 @@ services: vm: - docker-host00 container_name: radarr - image: lscr.io/linuxserver/radarr:latest + image: linuxserver/radarr:5.21.1 restart: unless-stopped volumes: - name: "Configuration" @@ -233,7 +233,7 @@ services: vm: - docker-host00 container_name: lidarr - image: lscr.io/linuxserver/lidarr:latest + image: linuxserver/lidarr:2.10.3 restart: unless-stopped volumes: - name: "Configuration" @@ -257,7 +257,7 @@ services: vm: - docker-host00 container_name: prowlarr - image: lscr.io/linuxserver/prowlarr:latest + image: linuxserver/prowlarr:1.32.2 restart: unless-stopped volumes: - name: "Configuration" @@ -275,7 +275,7 @@ services: vm: - docker-host00 container_name: paperless - image: ghcr.io/paperless-ngx/paperless-ngx:latest + image: ghcr.io/paperless-ngx/paperless-ngx:2.14 restart: unless-stopped depends_on: - paperless-postgres @@ -311,7 +311,7 @@ services: vm: - docker-host00 container_name: stirling - image: frooodle/s-pdf:latest + image: frooodle/s-pdf:0.45.0 restart: unless-stopped ports: - name: "http" @@ -321,7 +321,7 @@ services: vm: - docker-host01 container_name: gitea - image: gitea/gitea:1.23.1-rootless + image: gitea/gitea:1.23-rootless restart: unless-stopped volumes: - name: "Configuration" @@ -350,7 +350,7 @@ services: vm: - docker-host00 container_name: changedetection - image: dgtlmoon/changedetection.io + image: dgtlmoon/changedetection.io:0.49 restart: unless-stopped volumes: - name: "Data" @@ -364,7 +364,7 @@ services: vm: - docker-host00 container_name: gluetun - image: qmcgaw/gluetun + image: qmcgaw/gluetun:v3.40 restart: unless-stopped cap_add: - NET_ADMIN @@ -423,7 +423,7 @@ services: vm: - docker-host00 container_name: qbit - image: qbittorrentofficial/qbittorrent-nox + image: qbittorrentofficial/qbittorrent-nox:5.0.4-1 restart: unless-stopped depends_on: - gluetun @@ -449,9 +449,8 @@ services: vm: - docker-host00 - docker-host01 - - docker-host02 container_name: cadvisor - image: gcr.io/cadvisor/cadvisor:latest + image: gcr.io/cadvisor/cadvisor:v0.52.1 restart: unless-stopped ports: - name: "" @@ -470,79 +469,101 @@ services: - name: "Docker" internal: /var/lib/docker:ro external: /var/lib/docker - # - name: template - # vm: - # - - # container_name: - # image: - # restart: - # volumes: - # - name: - # internal: - # external: - # ports: - # - name: - # internal: - # external: - # environment: - # - - # - name: calibre - # vm: - # - docker-host00 - # container_name: calibre - # image: lscr.io/linuxserver/calibre-web:latest - # restart: unless-stopped - # volumes: - # - name: "Configuration" - # internal: /config" - # external: /opt/local/calibre/ - # - name: "Books" - # internal: /books" - # external: /media/docker/data/calibre/ - # ports: - # - name: "http" - # internal: 5000 - # external: 5000 - # environment: - # - PUID=1000 - # - PGID=1000 - # - TZ=Europe/Berlin - # - DOCKER_MODS=linuxserver/mods:universal-calibre - # - name: grafana - # vm: - # container_name: grafana - # image: grafana/grafana-oss - # restart: unless-stopped - # volumes: - # - name: "Configuration" - # internal: /etc/grafana/ - # external: /opt/docker/config/grafana/config/ - # - name: "Data" - # internal: /var/lib/grafana/ - # external: /media/docker/data/grafana/ - # ports: - # environment: - # - PUID=472 - # - PGID=472 - # - TZ=Europe/Berlin - # - name: prometheus - # vm: - # - docker-host00 - # container_name: prometheus - # image: prom/prometheus - # restart: unless-stopped - # volumes: - # - name: "Configuration" - # internal: /etc/prometheus/ - # external: /opt/docker/config/prometheus/ - # - name: "Data" - # internal: /prometheus/ - # external: prometheus_data - # ports: - # - name: "http" - # internal: 5000 - # external: 5000 - # environment: - # - PUID=65534 - # - PGID=65534 - # - TZ=Europe/Berlin +# - name: anubis +# vm: +# - docker-host00 +# - docker-host01 +# container_name: anubis +# image: ghcr.io/techarohq/anubis:v1.15.2 +# restart: unless-stopped +# ports: +# - name: "" +# internal: 8080 +# external: 8080 +# volumes: +# - name: "" +# internal: "/data/cfg/botPolicy.json:ro" +# external: "./botPolicy.json" +# environment: +# - BIND=":8080" +# - DIFFICULTY="5" +# - METRICS_BIND=":9090" +# - SERVE_ROBOTS_TXT="true" +# - TARGET="http://{{ hostvars[docker-lb].host.ip }}" +# - POLICY_FNAME="/data/cfg/botPolicy.json" +# - name: template +# vm: +# - +# container_name: +# image: +# restart: +# volumes: +# - name: +# internal: +# external: +# ports: +# - name: +# internal: +# external: +# environment: +# - +# - name: calibre +# vm: +# - docker-host00 +# container_name: calibre +# image: lscr.io/linuxserver/calibre-web:latest +# restart: unless-stopped +# volumes: +# - name: "Configuration" +# internal: /config" +# external: /opt/local/calibre/ +# - name: "Books" +# internal: /books" +# external: /media/docker/data/calibre/ +# ports: +# - name: "http" +# internal: 5000 +# external: 5000 +# environment: +# - PUID=1000 +# - PGID=1000 +# - TZ=Europe/Berlin +# - DOCKER_MODS=linuxserver/mods:universal-calibre +# - name: grafana +# vm: +# container_name: grafana +# image: grafana/grafana-oss +# restart: unless-stopped +# volumes: +# - name: "Configuration" +# internal: /etc/grafana/ +# external: /opt/docker/config/grafana/config/ +# - name: "Data" +# internal: /var/lib/grafana/ +# external: /media/docker/data/grafana/ +# ports: +# environment: +# - PUID=472 +# - PGID=472 +# - TZ=Europe/Berlin +# - name: prometheus +# vm: +# - docker-host00 +# container_name: prometheus +# image: prom/prometheus +# restart: unless-stopped +# volumes: +# - name: "Configuration" +# internal: /etc/prometheus/ +# external: /opt/docker/config/prometheus/ +# - name: "Data" +# internal: /prometheus/ +# external: prometheus_data +# ports: +# - name: "http" +# internal: 5000 +# external: 5000 +# environment: +# - PUID=65534 +# - PGID=65534 +# - TZ=Europe/Berlin diff --git a/group_vars/proxmox/secrets_vm.yml b/group_vars/proxmox/secrets_vm.yml new file mode 100644 index 0000000..2e302f5 --- /dev/null +++ b/group_vars/proxmox/secrets_vm.yml @@ -0,0 +1,8 @@ +$ANSIBLE_VAULT;1.1;AES256 +65336233643939653766663539646638346437653862656539666366353630376231353866336439 +3661363464343138333038633464646361616161376662610a303266333539306563393464613238 +36356264633564653265653632323664653133646261656234643235303165393666663539333938 +3665373736323262650a376564663737666339356666393934653234386234306334633864626130 +62663831633836373666303365643539336435393165343461346666636463653564343065653962 +62653163366663386234383462613837316166633735383862646238303263376464366564623631 +383264383961333035653539313266663463 diff --git a/group_vars/proxmox/vars.yml b/group_vars/proxmox/vars.yml index d3329f5..9564961 100644 --- a/group_vars/proxmox/vars.yml +++ b/group_vars/proxmox/vars.yml @@ -4,10 +4,19 @@ proxmox_api_password: "{{ vault.pve.aya01.root.sudo }}" proxmox_vms: - name: "test-vm-00" - hostname: "test-vm-00" - node: - - "aya01" - ostemplate: "" + node: "inko" + vmid: 950 + cores: 2 + cpu: "x86-64-v2-AES" + memory: 8192 # in MiB + net: + net0: "virtio,bridge=vmbr0,firewall=1" + scsi: + scsi0: "proxmox:64,format=qcow2" + scsihw: "virtio-scsi-single" + ostype: "l26" + sshkeys: "{{ pubkey }}" + ciuser: "{{ user }}" proxmox_lxcs: - name: "test-lxc-00" diff --git a/playbooks/proxmox.yml b/playbooks/proxmox.yml index 7706349..be440f8 100644 --- a/playbooks/proxmox.yml +++ b/playbooks/proxmox.yml @@ -5,6 +5,8 @@ vars_files: - secrets.yml roles: - - role: proxmox_vm + - role: proxmox tags: - - proxmox_vm + - proxmox + vars: + action: provision diff --git a/production.ini b/production.ini index 183cf78..deb6855 100644 --- a/production.ini +++ b/production.ini @@ -19,7 +19,7 @@ k3s-loadbalancer k3s-agent[00:02] k3s-server[00:02] k3s-longhorn[00:02] -docker-host[00:02] +docker-host[00:01] [k3s_nodes] k3s-server[00:02] @@ -27,7 +27,7 @@ k3s-agent[00:02] k3s-longhorn[00:02] [docker] -docker-host[00:02] +docker-host[00:01] docker-lb [vps] @@ -49,7 +49,7 @@ k3s-postgres k3s-loadbalancer [docker_host] -docker-host[00:02] +docker-host[00:01] [docker_lb] docker-lb diff --git a/roles/docker_host/handlers/main.yml b/roles/docker_host/handlers/main.yml index 4fff2cb..d60311a 100644 --- a/roles/docker_host/handlers/main.yml +++ b/roles/docker_host/handlers/main.yml @@ -8,4 +8,8 @@ - name: Restart compose community.docker.docker_compose_v2: project_src: "{{ docker.directories.compose }}" - state: restarted + state: present + retries: 3 + delay: 5 + register: result + until: result.rc == 0 diff --git a/roles/proxmox/files/check_proxmox_vm.sh b/roles/proxmox/files/check_proxmox_vm.sh new file mode 100755 index 0000000..6124842 --- /dev/null +++ b/roles/proxmox/files/check_proxmox_vm.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# Configuration +VM_ID=303 +TARGET_IP="192.168.20.36" # Replace with the IP of your VM +PORT=22 +CHECK_INTERVAL=300 # 5 minutes in seconds +LOG_FILE="/var/log/vm_monitor.log" + +# Function to log messages +log_message() { + echo "$(date): $1" | tee -a $LOG_FILE +} + +# Check if running on a Proxmox host +if ! command -v qm &>/dev/null; then + log_message "qm command not found. This script must run on a Proxmox host." + exit 1 +fi + +# Function to check port +check_port() { + # Try nc first if available + if command -v nc &>/dev/null; then + if nc -z -w 5 $TARGET_IP $PORT 2>/dev/null; then + return 0 # Port is open + else + return 1 # Port is closed + fi + # Fall back to nmap if nc is not available + elif command -v nmap &>/dev/null; then + if nmap -p $PORT $TARGET_IP | grep -q "$PORT/tcp.*open"; then + return 0 # Port is open + else + return 1 # Port is closed + fi + else + log_message "Neither nc nor nmap found. Please install one of them." + exit 1 + fi +} + +# Function to restart the VM +restart_vm() { + log_message "Port $PORT is not reachable. Restarting VM $VM_ID..." + + # Stop the VM + qm stop $VM_ID + if [ $? -ne 0 ]; then + log_message "Failed to stop VM $VM_ID. Trying force stop..." + qm stop $VM_ID --force + fi + + # Wait for VM to fully stop + log_message "Waiting for VM to stop..." + sleep 10 + + # Start the VM + qm start $VM_ID + if [ $? -ne 0 ]; then + log_message "Failed to start VM $VM_ID. Manual intervention required." + exit 1 + fi + + log_message "VM $VM_ID has been restarted." +} + +# Main loop +log_message "Starting monitoring of VM $VM_ID on port $PORT..." +log_message "Press Ctrl+C to exit." + +while true; do + # Check if port 22 is open + if ! check_port; then + restart_vm + else + log_message "Port $PORT is reachable. VM is running normally." + fi + + # Wait for the next check + log_message "Sleeping for $CHECK_INTERVAL seconds..." + sleep $CHECK_INTERVAL +done diff --git a/roles/proxmox/tasks/01_setup_user.yml b/roles/proxmox/tasks/01_setup_user.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/proxmox/tasks/10_create_secrets.yml b/roles/proxmox/tasks/10_create_secrets.yml new file mode 100644 index 0000000..4feec24 --- /dev/null +++ b/roles/proxmox/tasks/10_create_secrets.yml @@ -0,0 +1,33 @@ +--- +- name: Ensure Vault file exists + ansible.builtin.file: + path: "{{ proxmox_vault_file }}" + state: touch + mode: "0600" + +- name: Decrypt vm vault file + ansible.builtin.shell: cd ../; ansible-vault decrypt "./playbooks/{{ proxmox_vault_file }}" + ignore_errors: true + no_log: true + +- name: Load existing vault content + ansible.builtin.slurp: + src: "{{ proxmox_vault_file }}" + register: vault_content + no_log: true + +- name: Parse vault content as YAML + ansible.builtin.set_fact: + vault_data: "{{ (vault_content['content'] | b64decode | from_yaml) if (vault_content['content'] | length > 0) else {} }}" + no_log: true + +- name: Update Vault data + ansible.builtin.include_tasks: 15_create_secret.yml + loop: "{{ proxmox_vms | map(attribute='name') }}" + loop_control: + loop_var: "vm_name" + +- name: Encrypt vm vault file + ansible.builtin.shell: cd ../; ansible-vault encrypt "./playbooks/{{ proxmox_vault_file }}" + ignore_errors: true + no_log: true diff --git a/roles/proxmox/tasks/15_create_secret.yml b/roles/proxmox/tasks/15_create_secret.yml new file mode 100644 index 0000000..8e24190 --- /dev/null +++ b/roles/proxmox/tasks/15_create_secret.yml @@ -0,0 +1,26 @@ +--- +- name: Setup secret name + ansible.builtin.set_fact: + vm_name_secret: "{{ proxmox_secrets_prefix }}_{{ vm_name | replace('-','_') }}" + +- name: Check if variable is in vault + ansible.builtin.set_fact: + variable_exists: "{{ vm_name_secret in vault_data }}" + +- name: Set new secret + ansible.builtin.set_fact: + cipassword: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}" + when: not variable_exists + +- name: Set new secret + ansible.builtin.set_fact: + new_vault_data: "{{ vault_data | combine({ vm_name_secret: cipassword }) }}" + when: not variable_exists + +- name: Write updated Vault content to file (temporary plaintext) + ansible.builtin.copy: + content: "{{ new_vault_data | to_nice_yaml }}" + dest: "{{ proxmox_vault_file }}" + mode: "0600" + when: not variable_exists + no_log: true diff --git a/roles/proxmox/tasks/50_create_vms.yml b/roles/proxmox/tasks/50_create_vms.yml new file mode 100644 index 0000000..c407f40 --- /dev/null +++ b/roles/proxmox/tasks/50_create_vms.yml @@ -0,0 +1,11 @@ +--- +- name: Load vault variables + ansible.builtin.include_vars: + file: "{{ proxmox_vault_file }}" + name: vm_secrets + +- name: Create vms + ansible.builtin.include_tasks: 55_create_vm.yml + loop: "{{ proxmox_vms }}" + loop_control: + loop_var: "vm" diff --git a/roles/proxmox/tasks/55_create_vm.yml b/roles/proxmox/tasks/55_create_vm.yml new file mode 100644 index 0000000..cff235d --- /dev/null +++ b/roles/proxmox/tasks/55_create_vm.yml @@ -0,0 +1,34 @@ +- name: Create VM + community.general.proxmox_kvm: + api_user: root@pam + api_password: "{{ vault.pve.aya01.root.sudo }}" + api_host: "192.168.20.12" + name: "{{ vm.name }}" + vmid: "{{ vm.vmid }}" + node: "{{ vm.node }}" + cpu: "{{ vm.cpu }}" + cores: "{{ vm.cores }}" + memory: "{{ vm.memory }}" + net: "{{ vm.net }}" + scsi: "{{ vm.scsi }}" + scsihw: "{{ vm.scsihw }}" + ostype: "{{ vm.ostype }}" + sshkeys: "{{ vm.sshkeys }}" + tags: "{{ proxmox_tags }}" + ciuser: "{{ vm.ciuser }}" + cipassword: "{{ vm_secrets[proxmox_secrets_prefix + '_' + vm.name.replace('-', '_')] }}" + ide: + ide2: "proxmox:cloudinit,format=qcow2" + register: temp + +- name: Debug temp + ansible.builtin.debug: + msg: "{{ temp }}" + +- name: Set mac + ansible.builtin.set_fact: + mac: "{{ temp.mac }}" + +- name: debug mac + ansible.builtin.debug: + msg: "{{ mac }}" diff --git a/roles/proxmox/tasks/60_create_container.yml b/roles/proxmox/tasks/60_create_container.yml new file mode 100644 index 0000000..b9d4168 --- /dev/null +++ b/roles/proxmox/tasks/60_create_container.yml @@ -0,0 +1,11 @@ +--- +- name: Load vault variables + ansible.builtin.include_vars: + file: "{{ proxmox_vault_file }}" + name: vm_secrets + +- name: Create vms + ansible.builtin.include_tasks: 65_create_container.yml + loop: "{{ proxmox_lxcs }}" + loop_control: + loop_var: "container" diff --git a/roles/proxmox/tasks/65_create_containers.yml b/roles/proxmox/tasks/65_create_containers.yml new file mode 100644 index 0000000..fc03e7a --- /dev/null +++ b/roles/proxmox/tasks/65_create_containers.yml @@ -0,0 +1,4 @@ +--- +- name: Create Container + ansible.builtin.debug: + msg: "{{ container.name }}" diff --git a/roles/proxmox/tasks/90-download-image.yml b/roles/proxmox/tasks/90-download-image.yml new file mode 100644 index 0000000..f6222c6 --- /dev/null +++ b/roles/proxmox/tasks/90-download-image.yml @@ -0,0 +1,6 @@ +--- +- name: Download Debian Image + ansible.builtin.get_url: + url: "{{ proxmox_debian_image_url }}" + dest: "{{ proxmox_image_path }}" + mode: "0644" diff --git a/roles/proxmox/tasks/main.yml b/roles/proxmox/tasks/main.yml new file mode 100644 index 0000000..b7e78c8 --- /dev/null +++ b/roles/proxmox/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: Setup user + ansible.builtin.include_tasks: 01_setup_user.yml + +- name: Create VM vault + ansible.builtin.include_tasks: 10_create_secrets.yml + +- name: Create VMs + ansible.builtin.include_tasks: 50_create_vms.yml + +- name: Create LXC containers + ansible.builtin.include_tasks: 60_create_containers.yml diff --git a/roles/proxmox/vars/main.yml b/roles/proxmox/vars/main.yml new file mode 100644 index 0000000..1587e21 --- /dev/null +++ b/roles/proxmox/vars/main.yml @@ -0,0 +1,10 @@ +author: tuan-dat.tran@tudattr.dev +creator: ansible + +proxmox_vault_file: ../group_vars/proxmox/secrets_vm.yml +proxmox_secrets_prefix: secrets_vm +proxmox_debian_image_url: https://cdimage.debian.org/images/cloud/bookworm/20250316-2053/debian-12-genericcloud-amd64-20250316-2053.qcow2 +proxmox_image_path: /opt/template/iso/ + +proxmox_tags: + - "{{ creator }}" diff --git a/roles/proxmox_vm/tasks/create_vm.yml b/roles/proxmox_vm/tasks/create_vm.yml deleted file mode 100644 index 32cd4d1..0000000 --- a/roles/proxmox_vm/tasks/create_vm.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -# - name: Create VM -# community.general.proxmox: -# api_host: "{{ api_host }}" -# api_user: "{{ api_user }}" -# api_password: "{{ vault.proxmox.api_password }}" -# node: "{{ }}" diff --git a/roles/proxmox_vm/tasks/get_info.yml b/roles/proxmox_vm/tasks/get_info.yml deleted file mode 100644 index d1670e0..0000000 --- a/roles/proxmox_vm/tasks/get_info.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -- name: List existing nodes - community.general.proxmox_node_info: - api_host: "{{ proxmox_api_host }}" - api_user: "{{ proxmox_api_user }}@pam" - api_password: "{{ proxmox_api_password }}" - register: proxmox_nodes - -- name: Print info - ansible.builtin.debug: - msg: "{{ proxmox_nodes }}" diff --git a/roles/proxmox_vm/tasks/main.yml b/roles/proxmox_vm/tasks/main.yml deleted file mode 100644 index 8932427..0000000 --- a/roles/proxmox_vm/tasks/main.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -- name: Get info - ansible.builtin.include_tasks: get_info.yml -# - name: Create vm -# ansible.builtin.include_tasks: create_vm.yml -- 2.49.1 From 6934a9f5fc769535f96b4004f17b9cfdcf2607f0 Mon Sep 17 00:00:00 2001 From: Tuan-Dat Tran Date: Sun, 6 Apr 2025 23:46:28 +0200 Subject: [PATCH 3/8] distributed secrets to group_vars and added karakeep Signed-off-by: Tuan-Dat Tran --- group_vars/all/secrets.yml | 75 ++++----------------- group_vars/docker/secrets.yml | 32 +++++++++ group_vars/docker/vars.yml | 20 ++++++ group_vars/k3s/secrets.yml | 26 +++++++ group_vars/k3s/vars.yml | 2 +- group_vars/proxmox/secrets.yml | 15 +++++ group_vars/proxmox/secrets_vm.yml | 8 --- host_vars/k3s-agent00.yml | 2 +- host_vars/k3s-agent01.yml | 2 +- host_vars/k3s-agent02.yml | 2 +- host_vars/k3s-loadbalancer.yml | 2 +- host_vars/k3s-longhorn00.yml | 2 +- host_vars/k3s-longhorn01.yml | 2 +- host_vars/k3s-longhorn02.yml | 2 +- host_vars/k3s-postgres.yml | 2 +- host_vars/k3s-server00.yml | 2 +- host_vars/k3s-server01.yml | 2 +- host_vars/k3s-server02.yml | 2 +- roles/docker_host/templates/compose.yaml.j2 | 42 +++++++++--- roles/reverse_proxy/templates/Caddyfile.j2 | 6 +- 20 files changed, 154 insertions(+), 94 deletions(-) create mode 100644 group_vars/docker/secrets.yml create mode 100644 group_vars/k3s/secrets.yml create mode 100644 group_vars/proxmox/secrets.yml delete mode 100644 group_vars/proxmox/secrets_vm.yml diff --git a/group_vars/all/secrets.yml b/group_vars/all/secrets.yml index 7a8a6e3..b336136 100644 --- a/group_vars/all/secrets.yml +++ b/group_vars/all/secrets.yml @@ -1,63 +1,14 @@ $ANSIBLE_VAULT;1.1;AES256 -62353334666233376566326532636437376331316231323234643438323138316538363739343966 -3637633035343637363766613038346162336437303035390a663363313565343230346363646534 -39393835313839323534663430646461336536343764636463376262646666356465386234313635 -3965343062616437660a613633343839303638656464616638306234363732656139653736373262 -63643739313466353637613738343233353738373764653762343432643430383637313137376236 -37643033323439656161333361346638643562393031363230383033363862316162353132313161 -61323433643933323735376163666564666264666461666234376664323661333734313231623730 -65323839383932303436306434356334396130353236323965646564303930383765376265356438 -35633031623036313634333534663564653863366535643466306332386166666531343262386330 -32633530313666653462326565643163616632333835643231643063393438356265313638336662 -36376132353931613835343030633464633561613361376264613535383830376337303539316133 -64666164306235333663303564656364303762326262313835343233303465653934623965653933 -62336130653938643966656665306134376237376537663533306261623132653838363034626131 -39346339666566633037663730313732393464306438623630326533333866636465353631373435 -61623833393039393961633664383939623930633562383936373036616431333664376364663930 -36326666653431326332316361336439303163643061343435643363376665616135653036663466 -65613563356631633238303731366330303265396661303735616534653731616439613531353939 -35386562626432616239643665663432373536623064383963306537386338636437663439313066 -64373336373830633163633433666334393035336539363261336364376139373434316433643364 -35353035326134626661663730383132323466343938373562336332663964393164663731633231 -37386330363531616566663965613164663463303762363635323438366130336334323134393332 -37313638346162633561393562666334616464303330376230633264623262336335613063653665 -32393332396631363562643961336166666339326233366364333061303766616632323732666338 -39363864336634356535333063343730663231303839393061366238353032643965353939656135 -39316539333338333431383635323537653761356665343136303231633265643735623962346133 -66313132313765643231373435653266633564316331633563623138303835616133303061333239 -39333362323162303466383865343031663663613266643932653862623137663766343665366263 -66303962353330653162356333343231393137613763316134663135613738666231373835616563 -33656564343864333263646437656435363338376663636435353432643931303032306330353831 -37623634353735373635303934653034356431346330376637656435356530656131343736636463 -63376565333730623335386231333838353763633031663238346438643664373130343632313462 -39343033623939653865383965653331366539643934363236663631313537323338643266313030 -65363736653237336633343333393665333666386336666630366664313336393136383734613635 -62366365356262643632306430626166346636343837653730626665646631373966396535666336 -36396464626437393433656361386263613330333561643563643232333064333565626534353736 -32653239353531343265353631623430363537396233363666393335356261323532633432376139 -33663266303631383936623332313833616262616635356139336165323662656131643334633563 -39396538383661306564333239383131623039303835323636326532653331346135343065363533 -32616533643662643365383132666438383237396362653465666264346333383133653738643166 -61393561396535343230343665363235326561666565376165323262396638626631363032643865 -66656439626339653837353133626133326234333036386563353532383764613261326130363361 -39663233656538356334326530366132346339666161386433393431663262646433353430366532 -31336661316562323534356632616633363862366163346532613433393434323639313733656562 -37633962613630336661623733626237613365623436346662376135646563353735623030303064 -34303064323635306465326638633665333639306564343034646262326466323539643437646239 -65343865646137336564356438623739323639336437626564393337343232313563353762333561 -65633265386132666635303831653236346165623537343638326639383436326633323163643765 -63336439643465313039653362373538333834666432383533376233643031323665303161336630 -34643462376262363530633933393631343662393631356338316538333366303966623936633163 -31643663616536626538323033396564656432373938383637373831306432353034383630323133 -66646339636335623835636638653533323365323132383134636264396465393463353234363839 -62323236386235303830393930346632366331653632306633376335643232633432386536663630 -35393035303162666563653137613639636561396666623665323832636364336232333165336135 -36626465393762373064353561333939626638613335323066666366326539316438363736373331 -64303538663863613135303531326465666636386364356635316265373533366434323330323266 -39613464343138616235663035316538636137396532373365393866376666343631626333306436 -66383734303032343131356466333264393739663834393836376236656634373832356363343639 -61306436366665616438636539386363616166633536316533386332383632366265313161643965 -31386463323438336165383764396166393530623537666662353735646535653938383031333331 -32646431366166373264326564326630313634333639646662376165643861616139336231373432 -30666165373861343965333264303632623766633763376339353366313839336537616131616436 -6236303866623939313466633635633136383232363034376236 +65646664663537386235383334613536393336623332363437376337323235636335363165366632 +3433623633393731373932306433643663333133393734370a353261353164353335356264643234 +65376132336534306465376435303764616136646633303166336136373263346436353235343065 +6238353863333239330a303131623262353563323864323536313036356237653936326361366565 +62616566396266363535653062636537383061363438303138333237643939323162336465326363 +64323830393839386233303634326562386537373766646461376238663963376463623130303363 +65366638666132393538336361663639303831333232336632616338396539353565663239373265 +38323036343733303131383439323738623263383736303935636339303564343662633437626233 +33303564373963646465306137346161656166366266663766356362636362643430393232646635 +38363764386538613166306464336532623464343565396431643738353434313838633763663861 +35616365383831643434316436313035366131663131373064663464393031623132366137303333 +62333561373465323664303539353966663763613365373633373761343966656166363265313134 +6163 diff --git a/group_vars/docker/secrets.yml b/group_vars/docker/secrets.yml new file mode 100644 index 0000000..1c0b4ef --- /dev/null +++ b/group_vars/docker/secrets.yml @@ -0,0 +1,32 @@ +$ANSIBLE_VAULT;1.1;AES256 +30383661646632613539633934643164373364323632396664653738383461643436633438616663 +6532323935383966363234373262313135316338333163350a373034356562316438643339643731 +65323462663363313935313763643461633932323763633032346537653431643838643632316431 +3464646137303635300a613464346161636563343664386135663038346464343663323738356432 +66353638616631353765393462353234323437356666316332396661663063363435363039323966 +31303361323432333934353738613233363431366261623433356437626638353063623363373761 +63313437666132373762643530353432353066393861363964663531333439653939313563626334 +31646265316238626639316330373635396538666535373034366131353535343766663833656161 +35326364303262323133633236656632303537636665303061613362336631643261373061393462 +32343263623162643866366361376165633165383733663636363632393634316164356433343766 +30373634623161343363303936396436613265396432616432643064383231326561646533646532 +64393136313438343433643134666164373236383634333838363662323133343833363435306234 +39366662616634323837333231663964633834316163663036613433663630303566303330663765 +38346137393637323434396364333063393961393232363839636334643339333930363131396637 +63383034386535346337633263323130353338393135326535646134336264643136396331653337 +63643035393135623762663763306234313336326465623530393764663131636262386435316235 +38373761333762653531613365336234363238623864393062626166373862623239386164346465 +63393062343166306563636332643966336435303161636533316234353332646131373731313234 +33366465653663643938386439313134666662373865313061316135653639366161303631643436 +64656332616533333338336437323262336463653439613530366430633161616166626461333263 +36643231656133316135373936303361336535393661643363303636343331313461643561303266 +32303438333261613635373165636630363264376638633563353438663236663733346662303661 +35656265373530333063373136343132323461643136336137323361613166336461386565366562 +62343466643334636536653932373433356137373339333235656532643935373661663234633564 +31356630356164646533323134353138666563356431633262306465343731303937323439353236 +66323464633330363031383566313137303766373331653234396131366462633861653031316562 +65346537383436353333303062396139313036386562663630623834306635306230363661353965 +63613239663835623365393432336532636230386635313262623439386338623538626565613765 +63646334313933613963623961633831393737366166363366313138393436633537376166663365 +63333965363465376365353436326236343832653164393563653236376132393463616365616139 +623130306134323838303339653664646539 diff --git a/group_vars/docker/vars.yml b/group_vars/docker/vars.yml index b6e6938..aa57f4b 100644 --- a/group_vars/docker/vars.yml +++ b/group_vars/docker/vars.yml @@ -469,6 +469,26 @@ services: - name: "Docker" internal: /var/lib/docker:ro external: /var/lib/docker + - name: karakeep + vm: + - docker-host01 + container_name: karakeep + image: ghcr.io/karakeep-app/karakeep:0.23.2 + restart: unless-stopped + ports: + - name: "http" + internal: 3000 + external: 3000 + volumes: + - name: "Data" + internal: /data + external: /opt/local/karakeep/config + environment: + - MEILI_ADDR: http://karakeep-meilisearch:7700 + - BROWSER_WEB_URL: http://karakeep-chrome:9222 + - NEXTAUTH_SECRET: "{{ vault.docker.karakeep.nextauth_secret }}" + - MEILI_MASTER_KEY: "{{ vault.docker.karakeep.meili_master_key }}" + - NEXTAUTH_URL: http://localhost:3000 # - name: anubis # vm: # - docker-host00 diff --git a/group_vars/k3s/secrets.yml b/group_vars/k3s/secrets.yml new file mode 100644 index 0000000..712fa05 --- /dev/null +++ b/group_vars/k3s/secrets.yml @@ -0,0 +1,26 @@ +$ANSIBLE_VAULT;1.1;AES256 +66323965326561656434636164616434353663633933346332373537663136323465323461306337 +3733663066623866333534366430663761653262646662650a323938306636653965656361646330 +66313965376537643033666165366435653862663231383366636166373238666334313836313138 +6164353263323136300a653236636334643832396534623735316465623133373838353163313136 +33303331313037376336623637356633383734343338386634646335616632646366366138643539 +37303531346430323330396637316632643065346537386433663431373437376261366263306264 +63323235303632356661373463383565613764323733343839653139613766633036346234316432 +37626432333935613566386631346161623133366438343630316237363730626234336462303132 +38323132363631653432643462306133323266333637346139343961623430363436663763383234 +66343232386263646633653739343963333364386630376638396261326563333935643437646638 +63656664633838336535613963393434336264656265356238306237626361336533643363323838 +30376236613236386133383130633164306632323630383932383432353439646266386239383834 +32346431306662346166653738333138643733623739623536303639663136336533373230643533 +64323037303161306435316662653237356161393239656362383261306366336134353438326233 +62363532396336616261383735386535396363386339333962623233383534393033306662666266 +66316237616137366639333439613732666638376163373235306663323762613466363636346337 +38393762653537316134316234363066363439623164356237313566626533326332646663313838 +38383633616538353833353634376236656433383464303538613663383838633538616136313365 +64643438316638333433366137656634353039663763353734616432306465386563353665666136 +63383739323038333537396433303332343235383562376438633237663465396366643438353862 +32646637323530356432386662613366323234323639653139306665623865613666623133656465 +31636334666638623939393366663935363434613731386365303130343439376430613331663561 +30353738346138343563383738393666333761333231303366386563303165363039313263343563 +36303533353165323461376461623665313938356535363462663737643265636137613366616639 +38383761343161336462373563383338393435326331353132333336666330306638 diff --git a/group_vars/k3s/vars.yml b/group_vars/k3s/vars.yml index ca4888d..2146eca 100644 --- a/group_vars/k3s/vars.yml +++ b/group_vars/k3s/vars.yml @@ -3,7 +3,7 @@ db: user: "postgres" name: "k3s" user: "k3s" - password: "{{ vault.k3s.postgres.db.password }}" + password: "{{ vault_k3s.postgres.db.password }}" listen_address: "{{ k3s.db.ip }}" k3s: diff --git a/group_vars/proxmox/secrets.yml b/group_vars/proxmox/secrets.yml new file mode 100644 index 0000000..62d881d --- /dev/null +++ b/group_vars/proxmox/secrets.yml @@ -0,0 +1,15 @@ +$ANSIBLE_VAULT;1.1;AES256 +35333866323538343132373761316430616539643436646637633131366232346566656438303438 +3539333661363964633834613161626134323533653737650a613832323436663739663162303066 +31333130646631306539356233346632636132346539343734393065353033613865363466646632 +6565343937666530330a326130393934326435643837323631653862313232363466643534306131 +62376132383137336230366538326364663362346137613930633161663834393835623935373164 +65623564633765653137623361376130623363613263313835366464313039613532323661363461 +37366438616566643537656639316665363339633737363539636364316335663639303364663366 +62653734343364663830633534643931656439313763366138323663373464303137323864313637 +65316135343464393031343166366338323839326631623533343931353833643232643339386231 +38623735386465383964653663346631376531376261353933346661666131353533633331353437 +63336366623333653732306130316264393865633338653238303861646535343837396232366134 +63343037636361323239376436326431623165326366383561323832323730636532623039383734 +66663139656262643038303435346666323762343661336234663131343531636161636536646465 +6530333864323262363536393562346362306161653162346132 diff --git a/group_vars/proxmox/secrets_vm.yml b/group_vars/proxmox/secrets_vm.yml deleted file mode 100644 index 2e302f5..0000000 --- a/group_vars/proxmox/secrets_vm.yml +++ /dev/null @@ -1,8 +0,0 @@ -$ANSIBLE_VAULT;1.1;AES256 -65336233643939653766663539646638346437653862656539666366353630376231353866336439 -3661363464343138333038633464646361616161376662610a303266333539306563393464613238 -36356264633564653265653632323664653133646261656234643235303165393666663539333938 -3665373736323262650a376564663737666339356666393934653234386234306334633864626130 -62663831633836373666303365643539336435393165343461346666636463653564343065653962 -62653163366663386234383462613837316166633735383862646238303263376464366564623631 -383264383961333035653539313266663463 diff --git a/host_vars/k3s-agent00.yml b/host_vars/k3s-agent00.yml index f01b1ed..8568fbd 100644 --- a/host_vars/k3s-agent00.yml +++ b/host_vars/k3s-agent00.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.agent00.sudo }}" host: hostname: "k3s-agent00" diff --git a/host_vars/k3s-agent01.yml b/host_vars/k3s-agent01.yml index 3134d13..a97cf2d 100644 --- a/host_vars/k3s-agent01.yml +++ b/host_vars/k3s-agent01.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.agent01.sudo }}" host: hostname: "k3s-agent01" diff --git a/host_vars/k3s-agent02.yml b/host_vars/k3s-agent02.yml index de1d865..308b56c 100644 --- a/host_vars/k3s-agent02.yml +++ b/host_vars/k3s-agent02.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.agent02.sudo }}" host: hostname: "k3s-agent02" diff --git a/host_vars/k3s-loadbalancer.yml b/host_vars/k3s-loadbalancer.yml index 455ad44..d3e0d5d 100644 --- a/host_vars/k3s-loadbalancer.yml +++ b/host_vars/k3s-loadbalancer.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.loadbalancer.sudo }}" host: hostname: "k3s-loadbalancer" ip: "{{ ansible_host }}" diff --git a/host_vars/k3s-longhorn00.yml b/host_vars/k3s-longhorn00.yml index a13f2e5..bf32086 100644 --- a/host_vars/k3s-longhorn00.yml +++ b/host_vars/k3s-longhorn00.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.longhorn00.sudo }}" host: hostname: "k3s-longhorn00" diff --git a/host_vars/k3s-longhorn01.yml b/host_vars/k3s-longhorn01.yml index fc3688e..620ddd7 100644 --- a/host_vars/k3s-longhorn01.yml +++ b/host_vars/k3s-longhorn01.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.longhorn01.sudo }}" host: hostname: "k3s-longhorn01" diff --git a/host_vars/k3s-longhorn02.yml b/host_vars/k3s-longhorn02.yml index d7cd263..ed694ef 100644 --- a/host_vars/k3s-longhorn02.yml +++ b/host_vars/k3s-longhorn02.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.longhorn02.sudo }}" host: hostname: "k3s-longhorn02" diff --git a/host_vars/k3s-postgres.yml b/host_vars/k3s-postgres.yml index 5427603..133483b 100644 --- a/host_vars/k3s-postgres.yml +++ b/host_vars/k3s-postgres.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.postgres.sudo }}" host: hostname: "k3s-postgres" ip: "{{ ansible_host }}" diff --git a/host_vars/k3s-server00.yml b/host_vars/k3s-server00.yml index cb76120..3414658 100644 --- a/host_vars/k3s-server00.yml +++ b/host_vars/k3s-server00.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.server00.sudo }}" host: hostname: "k3s-server00" ip: "{{ ansible_host }}" diff --git a/host_vars/k3s-server01.yml b/host_vars/k3s-server01.yml index 3f34329..c0cc873 100644 --- a/host_vars/k3s-server01.yml +++ b/host_vars/k3s-server01.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.server01.sudo }}" host: hostname: "k3s-server01" diff --git a/host_vars/k3s-server02.yml b/host_vars/k3s-server02.yml index 93c03c5..307356e 100644 --- a/host_vars/k3s-server02.yml +++ b/host_vars/k3s-server02.yml @@ -3,7 +3,7 @@ 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 }}" +ansible_become_pass: "{{ vault_k3s.server02.sudo }}" host: hostname: "k3s-server02" diff --git a/roles/docker_host/templates/compose.yaml.j2 b/roles/docker_host/templates/compose.yaml.j2 index c86fb34..31036f9 100644 --- a/roles/docker_host/templates/compose.yaml.j2 +++ b/roles/docker_host/templates/compose.yaml.j2 @@ -1,12 +1,12 @@ services: {% for service in services %} {% if inventory_hostname in service.vm %} - {{service.name}}: + {{ service.name }}: container_name: {{ service.container_name }} image: {{ service.image }} restart: {{ service.restart }} {% if service.network_mode is not defined %} - hostname: {{service.name}} + hostname: {{ service.name }} networks: - net {% endif %} @@ -15,7 +15,7 @@ services: ports: {% for port in service.ports %} {% if port.internal != 'proxy_only' %} - - {{port.external}}:{{port.internal}} + - {{ port.external }}:{{ port.internal }} {% endif %} {% endfor %} {% endif %} @@ -41,24 +41,24 @@ services: {% if service.volumes is defined and service.volumes is iterable %} volumes: {% for volume in service.volumes %} - - {{volume.external}}:{{volume.internal}} + - {{ volume.external }}:{{ volume.internal }} {% endfor %} {% endif %} {% if service.environment is defined and service.environment is iterable %} environment: {% for env in service.environment %} - - {{env}} + - {{ env }} {% endfor %} {% endif %} {% if service.devices is defined and service.devices is iterable %} devices: {% for device in service.devices %} - - {{device.external}}:{{device.internal}} + - {{ device.external }}:{{ device.internal }} {% endfor %} {% endif %} {% if service.name == 'paperless' %} - {{service.name}}-broker: + {{ service.name }}-broker: container_name: paperless-broker image: docker.io/library/redis:7 restart: unless-stopped @@ -67,7 +67,7 @@ services: volumes: - /opt/local/paperless/redis/data:/data - {{service.name}}-postgres: + {{ service.name }}-postgres: container_name: paperless-postgres image: docker.io/library/postgres:15 restart: unless-stopped @@ -78,7 +78,31 @@ services: environment: POSTGRES_DB: paperless POSTGRES_USER: paperless - POSTGRES_PASSWORD: 5fnhn%u2YWY3paNvMAjdoufYPQ2Hf3Yi + POSTGRES_PASSWORD: {{ vault.docker.paperless.dbpass }} +{% endif %} +{% if service.name == 'karakeep' %} + + {{ service.name }}-chrome: + image: gcr.io/zenika-hub/alpine-chrome:123 + restart: unless-stopped + command: + - --no-sandbox + - --disable-gpu + - --disable-dev-shm-usage + - --remote-debugging-address=0.0.0.0 + - --remote-debugging-port=9222 + - --hide-scrollbars + + {{ service.name }}-meilisearch: + image: getmeili/meilisearch:v1.11.1 + restart: unless-stopped + environment: + MEILI_NO_ANALYTICS: "true" + NEXTAUTH_SECRET={{ vault.docker.karakeep.nextauth_secret }} + MEILI_MASTER_KEY={{ vault.docker.karakeep.meili_master_key }} + NEXTAUTH_URL=http://localhost:3000 + volumes: + - meilisearch:/meili_data {% endif %} {% endif %} diff --git a/roles/reverse_proxy/templates/Caddyfile.j2 b/roles/reverse_proxy/templates/Caddyfile.j2 index 389859c..1c52c80 100644 --- a/roles/reverse_proxy/templates/Caddyfile.j2 +++ b/roles/reverse_proxy/templates/Caddyfile.j2 @@ -18,9 +18,9 @@ } tls { dns netcup { - customer_number {{ vault.netcup.customer_number }} - api_key {{ vault.netcup.api_key}} - api_password {{ vault.netcup.api_password }} + customer_number {{ vault_netcup.customer_number }} + api_key {{ vault_netcup.api_key }} + api_password {{ vault_netcup.api_password }} } propagation_timeout 900s propagation_delay 600s -- 2.49.1 From 42196a32dc6d1365feb44972c98b800243685b8d Mon Sep 17 00:00:00 2001 From: Tuan-Dat Tran Date: Thu, 24 Apr 2025 20:24:33 +0200 Subject: [PATCH 4/8] feat(docker): Add karakeep and keycloak services Signed-off-by: Tuan-Dat Tran --- group_vars/docker/docker.yml | 521 ++++++++++++++++ group_vars/docker/keycloak.yml | 51 ++ group_vars/docker/port_mapping.yml | 19 + group_vars/docker/secrets.yml | 81 ++- group_vars/docker/vars.yml | 585 ------------------ roles/docker_host/handlers/main.yml | 2 - roles/docker_host/tasks/directory_setup.yml | 9 +- roles/docker_host/tasks/main.yml | 3 + roles/docker_host/tasks/provision.yml | 31 + roles/docker_host/templates/compose.yaml.j2 | 26 +- .../templates/keycloak/realm.json.j2 | 77 +++ 11 files changed, 776 insertions(+), 629 deletions(-) create mode 100644 group_vars/docker/docker.yml create mode 100644 group_vars/docker/keycloak.yml create mode 100644 group_vars/docker/port_mapping.yml create mode 100644 roles/docker_host/tasks/provision.yml create mode 100644 roles/docker_host/templates/keycloak/realm.json.j2 diff --git a/group_vars/docker/docker.yml b/group_vars/docker/docker.yml new file mode 100644 index 0000000..1fe0fed --- /dev/null +++ b/group_vars/docker/docker.yml @@ -0,0 +1,521 @@ +docker: + url: "https://download.docker.com/linux" + apt_release_channel: "stable" + directories: + local: "/opt/local/" + config: "/opt/docker/config/" + compose: "/opt/docker/compose/" + +services: + - name: syncthing + vm: + - docker-host00 + container_name: syncthing + image: syncthing/syncthing:1.29 + restart: unless-stopped + volumes: + - name: "Data" + internal: /var/syncthing/ + external: /media/docker/data/syncthing/ + ports: + - name: "http" + internal: 8384 + external: "{{ services_external_http.syncthing }}" + - 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.23.16 + restart: unless-stopped + volumes: + - name: "Data" + internal: /app/data + external: "{{ docker.directories.local }}/kuma/" + ports: + - name: "http" + internal: 3001 + external: "{{ services_external_http.kuma }}" + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin + - name: plex + vm: + - docker-host00 + container_name: plex + image: lscr.io/linuxserver/plex:1.41.5 + restart: unless-stopped + volumes: + - name: "Configuration" + internal: /config + external: "{{ docker.directories.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: "{{ services_external_http.plex }}" + - 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-host01 + container_name: jellyfin + image: jellyfin/jellyfin:10.10 + restart: "unless-stopped" + volumes: + - name: "Configuration" + internal: /config + external: "{{ docker.directories.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: "{{ services_external_http.jellyfin }}" + environment: + - name: hass + vm: + - docker-host01 + container_name: homeassistant + image: "ghcr.io/home-assistant/home-assistant:stable" + restart: unless-stopped + privileged: true + volumes: + - name: "Configuration" + internal: /config/ + external: "{{ docker.directories.local }}/home-assistant/config/" + - name: "Local Time" + internal: /etc/localtime:ro + external: /etc/localtime + ports: + - name: "http" + internal: 8123 + external: "{{ services_external_http.hass }}" + - 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: qmcgaw/ddns-updater:2 + restart: unless-stopped + volumes: + - name: "Configuration" + internal: /updater/data/" + external: "{{ docker.directories.config }}/ddns-updater/data/" + ports: + - name: "http" + internal: 8000 + external: "{{ services_external_http.ddns }}" + - name: sonarr + vm: + - docker-host00 + container_name: sonarr + image: linuxserver/sonarr:4.0.14 + restart: unless-stopped + volumes: + - name: "Configuration" + internal: /config + external: "{{ docker.directories.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: "{{ services_external_http.sonarr }}" + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin + - name: radarr + vm: + - docker-host00 + container_name: radarr + image: linuxserver/radarr:5.21.1 + restart: unless-stopped + volumes: + - name: "Configuration" + internal: /config + external: "{{ docker.directories.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: "{{ services_external_http.radarr }}" + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin + - name: lidarr + vm: + - docker-host00 + container_name: lidarr + image: linuxserver/lidarr:2.10.3 + restart: unless-stopped + volumes: + - name: "Configuration" + internal: /config + external: "{{ docker.directories.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: "{{ services_external_http.lidarr }}" + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin + - name: prowlarr + vm: + - docker-host00 + container_name: prowlarr + image: linuxserver/prowlarr:1.32.2 + restart: unless-stopped + volumes: + - name: "Configuration" + internal: /config + external: "{{ docker.directories.local }}/prowlarr/config" + ports: + - name: "http" + internal: 9696 + external: "{{ services_external_http.prowlarr }}" + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin + - name: paperless + vm: + - docker-host00 + container_name: paperless + image: ghcr.io/paperless-ngx/paperless-ngx:2.14 + restart: unless-stopped + depends_on: + - paperless-postgres + - paperless-broker + volumes: + - name: "Configuration" + internal: /usr/src/paperless/data + external: "{{ docker.directories.local }}/paperless/data/data" + - name: "Media" + internal: /usr/src/paperless/media + external: "{{ docker.directories.local }}/paperless/data/media" + - name: "Document Export" + internal: /usr/src/paperless/export + external: "{{ docker.directories.local }}/paperless/data/export" + - name: "Document Consume" + internal: /usr/src/paperless/consume + external: "{{ docker.directories.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: "{{ services_external_http.paperless }}" + - name: pdf + vm: + - docker-host00 + container_name: stirling + image: frooodle/s-pdf:0.45.0 + restart: unless-stopped + ports: + - name: "http" + internal: 8080 + external: "{{ services_external_http.pdf }}" + - name: git + vm: + - docker-host01 + container_name: gitea + image: gitea/gitea:1.23-rootless + restart: unless-stopped + volumes: + - name: "Configuration" + internal: /etc/gitea + external: "{{ docker.directories.local }}/gitea/config" + - name: "Data" + internal: /var/lib/gitea + external: "{{ docker.directories.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: "{{ services_external_http.git }}" + - 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:0.49 + restart: unless-stopped + volumes: + - name: "Data" + internal: /datastore + external: "{{ docker.directories.config }}/changedetection/data/" + ports: + - name: "http" + internal: 5000 + external: "{{ services_external_http.changedetection }}" + - name: gluetun + vm: + - docker-host00 + container_name: gluetun + image: qmcgaw/gluetun:v3.40 + 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:5.0.4-1 + 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 + container_name: cadvisor + image: gcr.io/cadvisor/cadvisor:v0.52.1 + 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: karakeep + vm: + - docker-host01 + container_name: karakeep + image: ghcr.io/karakeep-app/karakeep:0.23.2 + restart: unless-stopped + ports: + - name: "http" + internal: 3000 + external: "{{ services_external_http.karakeep }}" + volumes: + - name: "Data" + internal: /data + external: "{{ docker.directories.local }}/karakeep/config" + environment: + - MEILI_ADDR=http://karakeep-meilisearch:7700 + - BROWSER_WEB_URL=http://karakeep-chrome:9222 + - NEXTAUTH_SECRET={{ vault.docker.karakeep.nextauth_secret }} + - MEILI_MASTER_KEY={{ vault.docker.karakeep.meili_master_key }} + - NEXTAUTH_URL=https://karakeep.tudattr.dev/ + - OPENAI_API_KEY={{ vault.docker.karakeep.openai_key }} + - DATA_DIR=/data + - DISABLE_SIGNUPS=true + - name: keycloak + vm: + - docker-host01 + container_name: keycloak + image: quay.io/keycloak/keycloak:26.2 + restart: unless-stopped + ports: + - name: "http" + internal: 8080 + external: "{{ services_external_http.keycloak }}" + volumes: + - name: "config" + internal: /opt/keycloak/data/import/homelab-realm.json + external: "{{ docker.directories.local }}/keycloak/homelab-realm.json" + command: + - "start" + - "--import-realm" + environment: + - KC_DB=postgres + - KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak + - KC_DB_USERNAME=keycloak + - KC_DB_PASSWORD=password + - KC_HOSTNAME=keycloak.{{ internal_domain }} + - KC_HTTP_ENABLED=true + - KC_HTTP_RELATIVE_PATH=/ + - KC_PROXY=edge + - KC_PROXY_HEADERS=xforwarded + - KC_HOSTNAME_URL=https://keycloak.{{ internal_domain }} + - KC_HOSTNAME_ADMIN_URL=https://keycloak.{{ internal_domain }} + - KC_BOOTSTRAP_ADMIN_USERNAME=serviceadmin-{{ keycloak_admin_hash }} + - KC_BOOTSTRAP_ADMIN_PASSWORD={{ vault.docker.keycloak.admin.password } diff --git a/group_vars/docker/keycloak.yml b/group_vars/docker/keycloak.yml new file mode 100644 index 0000000..4909ae8 --- /dev/null +++ b/group_vars/docker/keycloak.yml @@ -0,0 +1,51 @@ +keycloak_admin_hash: "{{ vault.docker.keycloak.admin.hash }}" + +keycloak_config: + reals: + - realm: homelab + display_name: "Homelab Realm" + users: + - username: tudattr + password: "{{ vault.docker.keycloak.user.password }}" + realm_roles: + - offline_access + - uma_authorization + client_roles: + account: + - view-profile + - manage-account + admin: + username: "serviceadmin-{{ keycloak_admin_hash }}" + password: "{{ vault.docker.keycloak.admin.password }}" + realm_roles: + - offline_access + - uma_authorization + - admin + client_roles: + realm_management: + - realm-admin + account: + - view-profile + - manage-account + roles: + realm: + - name: admin + description: "Administrator role for the homelab realm" + default_roles: + - offline_access + - uma_authorization + - realm: master + display_name: "master" + admin: + username: "serviceadmin-{{ keycloak_admin_hash }}" + password: "{{ vault.docker.keycloak.admin.password }}" + realm_roles: + - offline_access + - uma_authorization + - admin + client_roles: + realm_management: + - realm-admin + account: + - view-profile + - manage-account diff --git a/group_vars/docker/port_mapping.yml b/group_vars/docker/port_mapping.yml new file mode 100644 index 0000000..a496330 --- /dev/null +++ b/group_vars/docker/port_mapping.yml @@ -0,0 +1,19 @@ +services_external_http: + syncthing: 8384 + kuma: 3001 + plex: 32400 + jellyfin: 8096 + hass: 8123 + ddns: 8001 + sonarr: 8989 + radarr: 7878 + lidarr: 8686 + prowlarr: 9696 + paperless: 8000 + pdf: 8080 + git: 3000 + changedetection: 5000 + torrentleech: 8083 + qbit: 8082 + karakeep: 3002 + keycloak: 3003 diff --git a/group_vars/docker/secrets.yml b/group_vars/docker/secrets.yml index 1c0b4ef..1d1db0d 100644 --- a/group_vars/docker/secrets.yml +++ b/group_vars/docker/secrets.yml @@ -1,32 +1,51 @@ $ANSIBLE_VAULT;1.1;AES256 -30383661646632613539633934643164373364323632396664653738383461643436633438616663 -6532323935383966363234373262313135316338333163350a373034356562316438643339643731 -65323462663363313935313763643461633932323763633032346537653431643838643632316431 -3464646137303635300a613464346161636563343664386135663038346464343663323738356432 -66353638616631353765393462353234323437356666316332396661663063363435363039323966 -31303361323432333934353738613233363431366261623433356437626638353063623363373761 -63313437666132373762643530353432353066393861363964663531333439653939313563626334 -31646265316238626639316330373635396538666535373034366131353535343766663833656161 -35326364303262323133633236656632303537636665303061613362336631643261373061393462 -32343263623162643866366361376165633165383733663636363632393634316164356433343766 -30373634623161343363303936396436613265396432616432643064383231326561646533646532 -64393136313438343433643134666164373236383634333838363662323133343833363435306234 -39366662616634323837333231663964633834316163663036613433663630303566303330663765 -38346137393637323434396364333063393961393232363839636334643339333930363131396637 -63383034386535346337633263323130353338393135326535646134336264643136396331653337 -63643035393135623762663763306234313336326465623530393764663131636262386435316235 -38373761333762653531613365336234363238623864393062626166373862623239386164346465 -63393062343166306563636332643966336435303161636533316234353332646131373731313234 -33366465653663643938386439313134666662373865313061316135653639366161303631643436 -64656332616533333338336437323262336463653439613530366430633161616166626461333263 -36643231656133316135373936303361336535393661643363303636343331313461643561303266 -32303438333261613635373165636630363264376638633563353438663236663733346662303661 -35656265373530333063373136343132323461643136336137323361613166336461386565366562 -62343466643334636536653932373433356137373339333235656532643935373661663234633564 -31356630356164646533323134353138666563356431633262306465343731303937323439353236 -66323464633330363031383566313137303766373331653234396131366462633861653031316562 -65346537383436353333303062396139313036386562663630623834306635306230363661353965 -63613239663835623365393432336532636230386635313262623439386338623538626565613765 -63646334313933613963623961633831393737366166363366313138393436633537376166663365 -63333965363465376365353436326236343832653164393563653236376132393463616365616139 -623130306134323838303339653664646539 +66363634613334353739343565353932393932633064623536666362323639643230343866313864 +6331373639363262343664396131626632653232666439630a663333323564343763303266626362 +30356631633633623535616136326438353166633637353339353461333439333364313437653364 +6565653535616330330a386639643730366535346233303463303030306437303931623839356538 +36666562353861373435366131373535613733323338393030396335646138653361653538386263 +63373763643031343831643339653964653337316264356536376261643664373465323231643534 +64646565643734613035326463653331613366356163326561383765653264336265313439346130 +39623661643264633838386362313866386536326461336232333564343634363437653863346664 +63376662643731663834303830393561353031653334386161663938636665383362313236626530 +34663231343039376639306264383539663263306166343335363663303664326631633534333263 +63613565656263623066376239313330313464303635613366613537333063616666393532363635 +65363237613262303161326530336464313262653665633630396562616534653464666638666138 +35396139363033353530353266376230366165653261323837303966623032356236303631363234 +63366338333266616263376636373836313333373936313562626237306631646434383738396537 +63333262306637326330623236323335326530383231626534616666616530373463656534336330 +37383239376237663730323137623638353062666566373464343935613239343038386335323064 +62653436343563643065373238326339663032636634326365393131373439343736633332366566 +64366635633939326262336238653531653738353263663539383361303466393661616231326532 +66666537653230396661616361653163663231653463336639343236333462656138386163346537 +62613866623862383236366161623939386337396133393563623133656461633036633731353234 +37643733343333613063656531356432363666383638343439396332316164633532383934663666 +32373039636232343930613762386339613963613933316130313565323364343863363139306262 +31636532306234613534366364386666366538663231386166666538633737373134396637306664 +62376537356137626366376636373564373039633135376462343865393831303733356165393938 +34633534356466313530333762333631336563346338613737633930386461346132613338346438 +64663362646364626362396264333563623263306133343438383166663339333133623639613435 +66373831353862323432666132626265656536653163343437373465303139326536326534373832 +63626137643031356335353137333962633535323331613038646265313037616431353761383465 +37623134656163613835353866313562623366336439386138646337363764333662346139323565 +34386463313730333761646465633936626436343166613636353938343039636239663031366335 +65336661343635346665393766623730316665323865643663623361666265373439376336396431 +34333035633337353663623966303738393261663433373039666539333861663538663431333664 +34363036313332616435383638353165663333343638356661326538333734313136636630623832 +37303663633433623638616364313239623736323832336161303735663030386138643636386633 +34396234363238623635633135373439643839333266643331633365326161353836643735636463 +63613538313839336337616561353836346339623761636630303037383766393362366636323533 +64333139623532346463346532316132323664366132646636636639636361653734343733386465 +39643437666464663930303934343239383539346638643332396166383737336461646333326335 +62626230396662366563356664366662396331613235356665376162626637613336333764313261 +32393663306163613235336262663562646636656366393538656561333139323339313233373833 +33376633303964356261656265653435663339333031323133656331663231626339633533396638 +33316339356339383031306535373434636464376337303938636261363833363830613464323263 +31353764353933656332353633393338386637373334623766396430646261666236333162633136 +64623034653163303166346235373335396533343461663763643664363561383331386335393631 +65333534636139356538306434356364656339313938383566343633626663376533373564636430 +35356539343233313234343232323465323433313839633764326433303732356665666630616534 +34343736663263303336656135393534366462323936383161646533623064376638346330396339 +64653066343062396135666335643533353439663535333037373661346166623030613235396433 +37653335666533373365633233393338376166343637393432383666313139643564383638333666 +3461306330623163336465303963643836653238306330363034 diff --git a/group_vars/docker/vars.yml b/group_vars/docker/vars.yml index aa57f4b..8bd5706 100644 --- a/group_vars/docker/vars.yml +++ b/group_vars/docker/vars.yml @@ -1,589 +1,4 @@ -docker: - url: "https://download.docker.com/linux" - apt_release_channel: "stable" - directories: - opt: "/opt/docker/" - compose: "/opt/docker/compose" - caddy: admin_email: me+acme@tudattr.dev domain: "seyshiro.de" - -services: - - name: syncthing - vm: - - docker-host00 - container_name: syncthing - image: syncthing/syncthing:1.29 - 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.23.16 - 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:1.41.5 - 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-host01 - container_name: jellyfin - image: jellyfin/jellyfin:10.10 - restart: "unless-stopped" - volumes: - - name: "Configuration" - internal: /config - external: /opt/local/jellyfin/config - - name: "Cache" - internal: /cache - external: /opt/docker/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-host01 - 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: qmcgaw/ddns-updater:2 - restart: unless-stopped - volumes: - - name: "Configuration" - internal: /updater/data/" - external: /opt/docker/config/ddns-updater/data/ - ports: - - name: "http" - internal: 8000 - external: 8001 - - name: sonarr - vm: - - docker-host00 - container_name: sonarr - image: linuxserver/sonarr:4.0.14 - 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: linuxserver/radarr:5.21.1 - 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: linuxserver/lidarr:2.10.3 - 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: linuxserver/prowlarr:1.32.2 - 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:2.14 - 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:0.45.0 - restart: unless-stopped - ports: - - name: "http" - internal: 8080 - external: 8080 - - name: git - vm: - - docker-host01 - container_name: gitea - image: gitea/gitea:1.23-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:0.49 - restart: unless-stopped - volumes: - - name: "Data" - internal: /datastore - external: /opt/docker/config/changedetection/data/ - ports: - - name: "http" - internal: 5000 - external: 5000 - - name: gluetun - vm: - - docker-host00 - container_name: gluetun - image: qmcgaw/gluetun:v3.40 - restart: unless-stopped - cap_add: - - NET_ADMIN - devices: - - name: "Tunnel" - internal: /dev/net/tun - external: /dev/net/tun - volumes: - - name: "Configuration" - internal: /gluetun - external: /opt/docker/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: /opt/docker/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:5.0.4-1 - restart: unless-stopped - depends_on: - - gluetun - network_mode: "container:gluetun" - volumes: - - name: "Configuration" - internal: /config - external: /opt/docker/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 - container_name: cadvisor - image: gcr.io/cadvisor/cadvisor:v0.52.1 - 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: karakeep - vm: - - docker-host01 - container_name: karakeep - image: ghcr.io/karakeep-app/karakeep:0.23.2 - restart: unless-stopped - ports: - - name: "http" - internal: 3000 - external: 3000 - volumes: - - name: "Data" - internal: /data - external: /opt/local/karakeep/config - environment: - - MEILI_ADDR: http://karakeep-meilisearch:7700 - - BROWSER_WEB_URL: http://karakeep-chrome:9222 - - NEXTAUTH_SECRET: "{{ vault.docker.karakeep.nextauth_secret }}" - - MEILI_MASTER_KEY: "{{ vault.docker.karakeep.meili_master_key }}" - - NEXTAUTH_URL: http://localhost:3000 -# - name: anubis -# vm: -# - docker-host00 -# - docker-host01 -# container_name: anubis -# image: ghcr.io/techarohq/anubis:v1.15.2 -# restart: unless-stopped -# ports: -# - name: "" -# internal: 8080 -# external: 8080 -# volumes: -# - name: "" -# internal: "/data/cfg/botPolicy.json:ro" -# external: "./botPolicy.json" -# environment: -# - BIND=":8080" -# - DIFFICULTY="5" -# - METRICS_BIND=":9090" -# - SERVE_ROBOTS_TXT="true" -# - TARGET="http://{{ hostvars[docker-lb].host.ip }}" -# - POLICY_FNAME="/data/cfg/botPolicy.json" -# - name: template -# vm: -# - -# container_name: -# image: -# restart: -# volumes: -# - name: -# internal: -# external: -# ports: -# - name: -# internal: -# external: -# environment: -# - -# - name: calibre -# vm: -# - docker-host00 -# container_name: calibre -# image: lscr.io/linuxserver/calibre-web:latest -# restart: unless-stopped -# volumes: -# - name: "Configuration" -# internal: /config" -# external: /opt/local/calibre/ -# - name: "Books" -# internal: /books" -# external: /media/docker/data/calibre/ -# ports: -# - name: "http" -# internal: 5000 -# external: 5000 -# environment: -# - PUID=1000 -# - PGID=1000 -# - TZ=Europe/Berlin -# - DOCKER_MODS=linuxserver/mods:universal-calibre -# - name: grafana -# vm: -# container_name: grafana -# image: grafana/grafana-oss -# restart: unless-stopped -# volumes: -# - name: "Configuration" -# internal: /etc/grafana/ -# external: /opt/docker/config/grafana/config/ -# - name: "Data" -# internal: /var/lib/grafana/ -# external: /media/docker/data/grafana/ -# ports: -# environment: -# - PUID=472 -# - PGID=472 -# - TZ=Europe/Berlin -# - name: prometheus -# vm: -# - docker-host00 -# container_name: prometheus -# image: prom/prometheus -# restart: unless-stopped -# volumes: -# - name: "Configuration" -# internal: /etc/prometheus/ -# external: /opt/docker/config/prometheus/ -# - name: "Data" -# internal: /prometheus/ -# external: prometheus_data -# ports: -# - name: "http" -# internal: 5000 -# external: 5000 -# environment: -# - PUID=65534 -# - PGID=65534 -# - TZ=Europe/Berlin diff --git a/roles/docker_host/handlers/main.yml b/roles/docker_host/handlers/main.yml index d60311a..44cc369 100644 --- a/roles/docker_host/handlers/main.yml +++ b/roles/docker_host/handlers/main.yml @@ -11,5 +11,3 @@ state: present retries: 3 delay: 5 - register: result - until: result.rc == 0 diff --git a/roles/docker_host/tasks/directory_setup.yml b/roles/docker_host/tasks/directory_setup.yml index 776f2f8..d4d3a6e 100644 --- a/roles/docker_host/tasks/directory_setup.yml +++ b/roles/docker_host/tasks/directory_setup.yml @@ -9,9 +9,9 @@ - /media/series - /media/movies - /media/songs - - "{{ docker.directories.opt }}" + - "{{ docker.directories.local }}" + - "{{ docker.directories.config }}" - "{{ docker.directories.compose }}" - - /opt/local become: true - name: Set ownership to {{ user }} @@ -20,8 +20,9 @@ owner: "{{ user }}" group: "{{ user }}" loop: - - "{{ docker.directories.opt }}" - - /opt/local + - "{{ docker.directories.local }}" + - "{{ docker.directories.config }}" + - "{{ docker.directories.compose }}" - /media become: true diff --git a/roles/docker_host/tasks/main.yml b/roles/docker_host/tasks/main.yml index 39f520b..2bc2612 100644 --- a/roles/docker_host/tasks/main.yml +++ b/roles/docker_host/tasks/main.yml @@ -11,6 +11,9 @@ - name: Setup directory structure for docker ansible.builtin.include_tasks: directory_setup.yml +- name: Deploy configs + ansible.builtin.include_tasks: provision.yml + - name: Deploy docker compose ansible.builtin.include_tasks: deploy_compose.yml diff --git a/roles/docker_host/tasks/provision.yml b/roles/docker_host/tasks/provision.yml new file mode 100644 index 0000000..28e94ea --- /dev/null +++ b/roles/docker_host/tasks/provision.yml @@ -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: Run Keycloak tasks + ansible.builtin.file: + path: "{{ docker.directories.local }}/keycloak/" + owner: "{{ user }}" + group: "{{ user }}" + state: directory + mode: "0755" + when: is_keycloak_host | bool + become: true + +- name: Run Keycloak tasks + ansible.builtin.template: + src: "templates/keycloak/realm.json.j2" + dest: "{{ docker.directories.local }}/keycloak/{{ keycloak.realm }}-realm.json" + owner: "{{ user }}" + group: "{{ user }}" + 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 diff --git a/roles/docker_host/templates/compose.yaml.j2 b/roles/docker_host/templates/compose.yaml.j2 index 31036f9..e177237 100644 --- a/roles/docker_host/templates/compose.yaml.j2 +++ b/roles/docker_host/templates/compose.yaml.j2 @@ -56,10 +56,16 @@ services: - {{ device.external }}:{{ device.internal }} {% endfor %} {% endif %} +{% if service.command is defined and service.command is iterable %} + command: +{% for command in service.command %} + - {{ command }} +{% endfor %} +{% endif %} {% if service.name == 'paperless' %} {{ service.name }}-broker: - container_name: paperless-broker + container_name: {{ service.name }}-broker image: docker.io/library/redis:7 restart: unless-stopped networks: @@ -68,7 +74,7 @@ services: - /opt/local/paperless/redis/data:/data {{ service.name }}-postgres: - container_name: paperless-postgres + container_name: {{ service.name }}-postgres image: docker.io/library/postgres:15 restart: unless-stopped networks: @@ -84,7 +90,10 @@ services: {{ service.name }}-chrome: image: gcr.io/zenika-hub/alpine-chrome:123 + container_name: {{ service.name }}-chrome restart: unless-stopped + networks: + - net command: - --no-sandbox - --disable-gpu @@ -95,14 +104,17 @@ services: {{ service.name }}-meilisearch: image: getmeili/meilisearch:v1.11.1 + container_name: {{ service.name }}-meilisearch restart: unless-stopped + networks: + - net environment: - MEILI_NO_ANALYTICS: "true" - NEXTAUTH_SECRET={{ vault.docker.karakeep.nextauth_secret }} - MEILI_MASTER_KEY={{ vault.docker.karakeep.meili_master_key }} - NEXTAUTH_URL=http://localhost:3000 + - MEILI_NO_ANALYTICS=true + - NEXTAUTH_SECRET={{ vault.docker.karakeep.nextauth_secret }} + - MEILI_MASTER_KEY={{ vault.docker.karakeep.meili_master_key }} + - OPENAI_API_KEY="{{ vault.docker.karakeep.openai_key }}" volumes: - - meilisearch:/meili_data + - /opt/local/karakeep/meili/data:/meili_data {% endif %} {% endif %} diff --git a/roles/docker_host/templates/keycloak/realm.json.j2 b/roles/docker_host/templates/keycloak/realm.json.j2 new file mode 100644 index 0000000..e77073d --- /dev/null +++ b/roles/docker_host/templates/keycloak/realm.json.j2 @@ -0,0 +1,77 @@ +{ + "realm": "{{ keycloak.realm }}", + "enabled": true, + "displayName": "{{ keycloak.display_name }}", + "displayNameHtml": "
{{keycloak.display_name}}
", + "bruteForceProtected": true, + "users": [ + {%- 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 %} + ] + } + }, + {% endfor %} + { + "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 %} + ] +} -- 2.49.1 From a2a58f6343bf3faac8e6e0d9231ca24c731b83bb Mon Sep 17 00:00:00 2001 From: Tuan-Dat Tran Date: Fri, 25 Apr 2025 23:36:44 +0200 Subject: [PATCH 5/8] feat(keycloak|docker): improved templating Signed-off-by: Tuan-Dat Tran --- group_vars/docker/docker.yml | 57 +++++----- group_vars/docker/keycloak.yml | 12 +- group_vars/docker/secrets.yml | 105 +++++++++--------- roles/docker_host/templates/compose.yaml.j2 | 66 +++++------ .../templates/keycloak/realm.json.j2 | 48 ++++---- 5 files changed, 157 insertions(+), 131 deletions(-) diff --git a/group_vars/docker/docker.yml b/group_vars/docker/docker.yml index 1fe0fed..61df020 100644 --- a/group_vars/docker/docker.yml +++ b/group_vars/docker/docker.yml @@ -12,7 +12,6 @@ services: - docker-host00 container_name: syncthing image: syncthing/syncthing:1.29 - restart: unless-stopped volumes: - name: "Data" internal: /var/syncthing/ @@ -39,7 +38,6 @@ services: - docker-host00 container_name: kuma image: louislam/uptime-kuma:1.23.16 - restart: unless-stopped volumes: - name: "Data" internal: /app/data @@ -57,7 +55,6 @@ services: - docker-host00 container_name: plex image: lscr.io/linuxserver/plex:1.41.5 - restart: unless-stopped volumes: - name: "Configuration" internal: /config @@ -110,7 +107,6 @@ services: - docker-host01 container_name: jellyfin image: jellyfin/jellyfin:10.10 - restart: "unless-stopped" volumes: - name: "Configuration" internal: /config @@ -141,7 +137,6 @@ services: - docker-host01 container_name: homeassistant image: "ghcr.io/home-assistant/home-assistant:stable" - restart: unless-stopped privileged: true volumes: - name: "Configuration" @@ -168,7 +163,6 @@ services: - docker-host00 container_name: ddns-updater image: qmcgaw/ddns-updater:2 - restart: unless-stopped volumes: - name: "Configuration" internal: /updater/data/" @@ -182,7 +176,6 @@ services: - docker-host00 container_name: sonarr image: linuxserver/sonarr:4.0.14 - restart: unless-stopped volumes: - name: "Configuration" internal: /config @@ -206,7 +199,6 @@ services: - docker-host00 container_name: radarr image: linuxserver/radarr:5.21.1 - restart: unless-stopped volumes: - name: "Configuration" internal: /config @@ -230,7 +222,6 @@ services: - docker-host00 container_name: lidarr image: linuxserver/lidarr:2.10.3 - restart: unless-stopped volumes: - name: "Configuration" internal: /config @@ -254,7 +245,6 @@ services: - docker-host00 container_name: prowlarr image: linuxserver/prowlarr:1.32.2 - restart: unless-stopped volumes: - name: "Configuration" internal: /config @@ -272,10 +262,9 @@ services: - docker-host00 container_name: paperless image: ghcr.io/paperless-ngx/paperless-ngx:2.14 - restart: unless-stopped depends_on: - paperless-postgres - - paperless-broker + - paperless-redis volumes: - name: "Configuration" internal: /usr/src/paperless/data @@ -290,7 +279,7 @@ services: internal: /usr/src/paperless/consume external: "{{ docker.directories.local }}/paperless/data/consume" environment: - - "PAPERLESS_REDIS=redis://paperless-broker:6379" + - "PAPERLESS_REDIS=redis://paperless-redis:6379" - "PAPERLESS_DBHOST=paperless-postgres" - "PAPERLESS_DBUSER=paperless" - "PAPERLESS_DBPASS={{ vault.docker.paperless.dbpass }}" @@ -303,12 +292,18 @@ services: - name: "http" internal: 8000 external: "{{ services_external_http.paperless }}" + sub_service: + - name: postgres + version: 15 + username: paperless + password: "{{ vault.docker.paperless.dbpass }}" + - name: redis + version: 7 - name: pdf vm: - docker-host00 container_name: stirling image: frooodle/s-pdf:0.45.0 - restart: unless-stopped ports: - name: "http" internal: 8080 @@ -318,7 +313,6 @@ services: - docker-host01 container_name: gitea image: gitea/gitea:1.23-rootless - restart: unless-stopped volumes: - name: "Configuration" internal: /etc/gitea @@ -347,7 +341,6 @@ services: - docker-host00 container_name: changedetection image: dgtlmoon/changedetection.io:0.49 - restart: unless-stopped volumes: - name: "Data" internal: /datastore @@ -361,7 +354,6 @@ services: - docker-host00 container_name: gluetun image: qmcgaw/gluetun:v3.40 - restart: unless-stopped cap_add: - NET_ADMIN devices: @@ -394,7 +386,6 @@ services: - docker-host00 container_name: torrentleech image: qbittorrentofficial/qbittorrent-nox - restart: unless-stopped depends_on: - gluetun network_mode: "container:gluetun" @@ -420,7 +411,6 @@ services: - docker-host00 container_name: qbit image: qbittorrentofficial/qbittorrent-nox:5.0.4-1 - restart: unless-stopped depends_on: - gluetun network_mode: "container:gluetun" @@ -447,7 +437,6 @@ services: - docker-host01 container_name: cadvisor image: gcr.io/cadvisor/cadvisor:v0.52.1 - restart: unless-stopped ports: - name: "" internal: 8080 @@ -470,7 +459,6 @@ services: - docker-host01 container_name: karakeep image: ghcr.io/karakeep-app/karakeep:0.23.2 - restart: unless-stopped ports: - name: "http" internal: 3000 @@ -488,12 +476,21 @@ services: - OPENAI_API_KEY={{ vault.docker.karakeep.openai_key }} - DATA_DIR=/data - DISABLE_SIGNUPS=true + sub_service: + - name: meilisearch + version: v1.11.1 + nextauth_secret: "{{ vault.docker.karakeep.nextauth_secret }}" + meili_master_key: "{{ vault.docker.karakeep.meili_master_key }}" + openai_key: "{{ vault.docker.karakeep.openai_key }}" + - name: chrome + version: 123 - name: keycloak vm: - docker-host01 container_name: keycloak image: quay.io/keycloak/keycloak:26.2 - restart: unless-stopped + depends_on: + - keycloak-postgres ports: - name: "http" internal: 8080 @@ -502,14 +499,17 @@ services: - name: "config" internal: /opt/keycloak/data/import/homelab-realm.json external: "{{ docker.directories.local }}/keycloak/homelab-realm.json" + - name: "config" + internal: /opt/keycloak/data/import/master-realm.json + external: "{{ docker.directories.local }}/keycloak/master-realm.json" command: - "start" - "--import-realm" environment: - KC_DB=postgres - - KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak - - KC_DB_USERNAME=keycloak - - KC_DB_PASSWORD=password + - KC_DB_URL=jdbc:postgresql://keycloak-postgres:5432/keycloak + - KC_DB_USERNAME={{ keycloak_config.database.username }} + - KC_DB_PASSWORD={{ keycloak_config.database.password }} - KC_HOSTNAME=keycloak.{{ internal_domain }} - KC_HTTP_ENABLED=true - KC_HTTP_RELATIVE_PATH=/ @@ -518,4 +518,9 @@ services: - KC_HOSTNAME_URL=https://keycloak.{{ internal_domain }} - KC_HOSTNAME_ADMIN_URL=https://keycloak.{{ internal_domain }} - KC_BOOTSTRAP_ADMIN_USERNAME=serviceadmin-{{ keycloak_admin_hash }} - - KC_BOOTSTRAP_ADMIN_PASSWORD={{ vault.docker.keycloak.admin.password } + - KC_BOOTSTRAP_ADMIN_PASSWORD={{ vault.docker.keycloak.admin.password }} + sub_service: + - name: postgres + version: 17 + username: "{{ keycloak_config.database.username }}" + password: "{{ keycloak_config.database.password }}" diff --git a/group_vars/docker/keycloak.yml b/group_vars/docker/keycloak.yml index 4909ae8..d1c0205 100644 --- a/group_vars/docker/keycloak.yml +++ b/group_vars/docker/keycloak.yml @@ -1,7 +1,13 @@ keycloak_admin_hash: "{{ vault.docker.keycloak.admin.hash }}" +keycloak_realms: "{{ keycloak_config.realms }}" + keycloak_config: - reals: + database: + db_name: keycloak + username: keycloak + password: "{{ vault.docker.keycloak.database.password }}" + realms: - realm: homelab display_name: "Homelab Realm" users: @@ -42,6 +48,7 @@ keycloak_config: realm_roles: - offline_access - uma_authorization + - create-realm - admin client_roles: realm_management: @@ -49,3 +56,6 @@ keycloak_config: account: - view-profile - manage-account + roles: + realm: [] + default_roles: [] diff --git a/group_vars/docker/secrets.yml b/group_vars/docker/secrets.yml index 1d1db0d..e423c00 100644 --- a/group_vars/docker/secrets.yml +++ b/group_vars/docker/secrets.yml @@ -1,51 +1,56 @@ $ANSIBLE_VAULT;1.1;AES256 -66363634613334353739343565353932393932633064623536666362323639643230343866313864 -6331373639363262343664396131626632653232666439630a663333323564343763303266626362 -30356631633633623535616136326438353166633637353339353461333439333364313437653364 -6565653535616330330a386639643730366535346233303463303030306437303931623839356538 -36666562353861373435366131373535613733323338393030396335646138653361653538386263 -63373763643031343831643339653964653337316264356536376261643664373465323231643534 -64646565643734613035326463653331613366356163326561383765653264336265313439346130 -39623661643264633838386362313866386536326461336232333564343634363437653863346664 -63376662643731663834303830393561353031653334386161663938636665383362313236626530 -34663231343039376639306264383539663263306166343335363663303664326631633534333263 -63613565656263623066376239313330313464303635613366613537333063616666393532363635 -65363237613262303161326530336464313262653665633630396562616534653464666638666138 -35396139363033353530353266376230366165653261323837303966623032356236303631363234 -63366338333266616263376636373836313333373936313562626237306631646434383738396537 -63333262306637326330623236323335326530383231626534616666616530373463656534336330 -37383239376237663730323137623638353062666566373464343935613239343038386335323064 -62653436343563643065373238326339663032636634326365393131373439343736633332366566 -64366635633939326262336238653531653738353263663539383361303466393661616231326532 -66666537653230396661616361653163663231653463336639343236333462656138386163346537 -62613866623862383236366161623939386337396133393563623133656461633036633731353234 -37643733343333613063656531356432363666383638343439396332316164633532383934663666 -32373039636232343930613762386339613963613933316130313565323364343863363139306262 -31636532306234613534366364386666366538663231386166666538633737373134396637306664 -62376537356137626366376636373564373039633135376462343865393831303733356165393938 -34633534356466313530333762333631336563346338613737633930386461346132613338346438 -64663362646364626362396264333563623263306133343438383166663339333133623639613435 -66373831353862323432666132626265656536653163343437373465303139326536326534373832 -63626137643031356335353137333962633535323331613038646265313037616431353761383465 -37623134656163613835353866313562623366336439386138646337363764333662346139323565 -34386463313730333761646465633936626436343166613636353938343039636239663031366335 -65336661343635346665393766623730316665323865643663623361666265373439376336396431 -34333035633337353663623966303738393261663433373039666539333861663538663431333664 -34363036313332616435383638353165663333343638356661326538333734313136636630623832 -37303663633433623638616364313239623736323832336161303735663030386138643636386633 -34396234363238623635633135373439643839333266643331633365326161353836643735636463 -63613538313839336337616561353836346339623761636630303037383766393362366636323533 -64333139623532346463346532316132323664366132646636636639636361653734343733386465 -39643437666464663930303934343239383539346638643332396166383737336461646333326335 -62626230396662366563356664366662396331613235356665376162626637613336333764313261 -32393663306163613235336262663562646636656366393538656561333139323339313233373833 -33376633303964356261656265653435663339333031323133656331663231626339633533396638 -33316339356339383031306535373434636464376337303938636261363833363830613464323263 -31353764353933656332353633393338386637373334623766396430646261666236333162633136 -64623034653163303166346235373335396533343461663763643664363561383331386335393631 -65333534636139356538306434356364656339313938383566343633626663376533373564636430 -35356539343233313234343232323465323433313839633764326433303732356665666630616534 -34343736663263303336656135393534366462323936383161646533623064376638346330396339 -64653066343062396135666335643533353439663535333037373661346166623030613235396433 -37653335666533373365633233393338376166343637393432383666313139643564383638333666 -3461306330623163336465303963643836653238306330363034 +32623863646365383136636631383936353032333935623162386465643139663835303063666138 +3336626338376466386265663737383062653236383430310a633138323038626134636362616166 +37383831323239366338333038326665643932643237656265316361323466376636373662343761 +6234366130373535330a343432663638393566613963303530653937613139366330653933376137 +65356265306139326361336632323332663135373735626539376565313466323236323862623531 +65623932633936666338653164646661373937376133333937336434613264393637363065353462 +31376333336433643432626531373731656238336431376630653832363437646665353333313764 +63656565326636383537373736303933636264633939323262656363346639376439383632386530 +64373230623135316634323565623736386263613630383038643636323965326464333533333136 +30346132616237356662626462363266376261333434663634353330613137626538376433333235 +63346434386538663335333262386536663330653835343335323636363233333135626434356131 +61346465643231646338346435396662323834373634613834393231326531666637636566316434 +66663737643037336332313338663739653939333866383835663835386165373664623433623237 +35353734616431666561656231336463336234656362623265356361626161383136653064616664 +35623638653935643465646538653931643935313638366133343233616565623433376435323739 +31376236626131623765303761396666346330633734373137366366336265663361613337366236 +35356239373361666337663661333834623039323639373131363638393435303161636336316639 +35376231366162626536396130666631323337313034363066303737613764336232383235613764 +66356530333733363030396633626438326134356535653538363561643837303462653732376462 +64663034653135386364643434653162343338343437323062396565643466643264653165393064 +32333561303035626463363461303866316465323966636166376432616532353438656633346363 +62656464303165646463336636386630333561373537386330663531616466643164623865393233 +66356337633238316235636632626234313938386338363164613231336434396566666666616538 +32396235383930306362343466656535393036303931663063626465373831636134346237346530 +64396464323538333433636461303231306538373861393932636336313061383032323662633432 +39376265353734333339313266353964383830373665373234633236613830636432326636353933 +65656238393438633862366363366665643364313534623833656634393035336634663837656661 +33643338393330376464356232633638303732626336383936626662313430303338373438653865 +62613765626332396636636433623364386135316265643163326534646138663930306363353737 +33353537396135386637313132393365616638323330313966323461383666326664303231353734 +34336663333865346538386663316638306239343832616231323730393363353933393365653830 +31393933313963396236653234383564376264616332373230663961313638343933336261646435 +35386437336130376139646563383137666466356361386366323735346130613866313330306631 +62383566363832333633653564313936363564346166663931653831616634633135353565306464 +64613863343766613764623461633335643137363065643864313337653665346230363331626434 +30306235343661393336656434666637623930333038393865653865643836613235366562386232 +39653336633034646233353633323135336639653062356233643131346666376664356262343938 +32396335356532323231646330383734666435666164643731323634326134393732316131353836 +65633631326133663633376361373631653739613633313161313935323066643530356337613835 +64316431653437653163626234386164303465353731616530623863323937343565666339323639 +31343562373433303535626465333936373433323834363965323732336535333565616231316235 +39663431356633326466393862383133313030656431333839396333326461323130366533306139 +31316338323333356334623332663166323035373864313739363335356162633937613164373637 +62643538323066363734353136323537613263306138613761643865383062343934313666316530 +65666166303263643163633666323861633765626438343739613164386333316335323963326334 +31663433653534383866666639353036616565363230626136626330303061623936363531333139 +65376333616331316637633461623836663965633462383830633165376631356631396564323330 +66346561613133353438653365333361643166393535393466373330316136376263643163666139 +64656233326333656438613235303937653363323761636666373633623938656134366262323931 +35323133373163393964323962346433366434623636383133323535363632363465663862306439 +33633564643030306638343430313831376333613363643839303330343338393964623038343165 +39346233303864393537316531396333356363373565626530633237653337393434653034633263 +32386431613462363430623761333961393834353664626238653063336536653531626266613463 +30623438313430663165303064336532613637613566623864643730633232353538336131666566 +366331336161363266613532653336343131 diff --git a/roles/docker_host/templates/compose.yaml.j2 b/roles/docker_host/templates/compose.yaml.j2 index e177237..9648015 100644 --- a/roles/docker_host/templates/compose.yaml.j2 +++ b/roles/docker_host/templates/compose.yaml.j2 @@ -1,10 +1,11 @@ services: {% for service in services %} {% if inventory_hostname in service.vm %} + {{ service.name }}: container_name: {{ service.container_name }} image: {{ service.image }} - restart: {{ service.restart }} + restart: unless-stopped {% if service.network_mode is not defined %} hostname: {{ service.name }} networks: @@ -62,34 +63,37 @@ services: - {{ command }} {% endfor %} {% endif %} -{% if service.name == 'paperless' %} - - {{ service.name }}-broker: - container_name: {{ service.name }}-broker - image: docker.io/library/redis:7 - restart: unless-stopped - networks: - - net - volumes: - - /opt/local/paperless/redis/data:/data - +{% if service.sub_service is defined and service.sub_service is iterable %} +{% for sub in service.sub_service %} +{% if sub.name is defined and sub.name == "postgres" %} {{ service.name }}-postgres: container_name: {{ service.name }}-postgres - image: docker.io/library/postgres:15 + image: docker.io/library/postgres:{{ sub.version }} restart: unless-stopped + hostname: {{ service.name }}-postgres networks: - net volumes: - - /opt/local/paperless/db/data:/var/lib/postgresql/data + - /opt/local/{{ service.name }}/postgres/data:/var/lib/postgresql/data environment: - POSTGRES_DB: paperless - POSTGRES_USER: paperless - POSTGRES_PASSWORD: {{ vault.docker.paperless.dbpass }} + POSTGRES_DB: {{ service.name }} + POSTGRES_USER: {{ sub.username }} + POSTGRES_PASSWORD: {{ sub.password }} {% endif %} -{% if service.name == 'karakeep' %} - +{% 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:123 + image: gcr.io/zenika-hub/alpine-chrome:{{ sub.version }} container_name: {{ service.name }}-chrome restart: unless-stopped networks: @@ -101,22 +105,25 @@ services: - --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: - image: getmeili/meilisearch:v1.11.1 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={{ vault.docker.karakeep.nextauth_secret }} - - MEILI_MASTER_KEY={{ vault.docker.karakeep.meili_master_key }} - - OPENAI_API_KEY="{{ vault.docker.karakeep.openai_key }}" - volumes: - - /opt/local/karakeep/meili/data:/meili_data + - NEXTAUTH_SECRET={{ sub.nextauth_secret }} + - MEILI_MASTER_KEY={{ sub.meili_master_key }} + - OPENAI_API_KEY="{{ sub.openai_key }}" +{% endif %} +{% endfor %} {% endif %} - {% endif %} {% endfor %} networks: @@ -126,6 +133,3 @@ networks: driver: default config: - subnet: 172.16.69.0/24 - -volumes: - prometheus_data: {} diff --git a/roles/docker_host/templates/keycloak/realm.json.j2 b/roles/docker_host/templates/keycloak/realm.json.j2 index e77073d..579c9b0 100644 --- a/roles/docker_host/templates/keycloak/realm.json.j2 +++ b/roles/docker_host/templates/keycloak/realm.json.j2 @@ -5,7 +5,8 @@ "displayNameHtml": "
{{keycloak.display_name}}
", "bruteForceProtected": true, "users": [ - {%- for user in keycloak.users %} +{% if keycloak.users is defined and keycloak.users is iterable %} +{% for user in keycloak.users %} { "username": "{{ user.username }}", "enabled": true, @@ -17,19 +18,20 @@ } ], "realmRoles": [ - {%- for realm_role in user.realm_roles %} - "{{ realm_role }}"{%- if not loop.last %},{%- endif %} - {% endfor %} +{% 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 %} +{% for account in user.client_roles.account %} + "{{ account }}"{%- if not loop.last %},{% endif %}{{''}} +{% endfor %} ] } - }, - {% endfor %} + },{% if not loop.last %}{% endif %} +{% endfor %} +{% endif %} { "username": "{{ keycloak.admin.username }}", "enabled": true, @@ -41,37 +43,37 @@ } ], "realmRoles": [ - {%- for realm_role in keycloak.admin.realm_roles %} - "{{ realm_role }}"{% if not loop.last %},{% endif %} - {% endfor %} +{% 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 %} +{% 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 %} +{% for account in keycloak.admin.client_roles.account %} + "{{ account }}"{%- if not loop.last %},{% endif %}{{''}} +{% endfor %} ] } } ], "roles": { "realm": [ - {%- for role in keycloak.roles.realm %} +{% for role in keycloak.roles.realm %} { "name": "{{ role.name }}", "description": "{{ role.name }}" }{% if not loop.last %},{% endif %} - {% endfor %} +{% endfor %} ] }, "defaultRoles": [ - {%- for role in keycloak.roles.default_roles %} - "{{ role }}"{% if not loop.last %},{% endif %} - {% endfor %} +{% for role in keycloak.roles.default_roles %} + "{{ role }}"{% if not loop.last %},{% endif %}{{''}} +{% endfor %} ] } -- 2.49.1 From 0e8e07ed3e7353396166dfa1a887a7694c74ef3b Mon Sep 17 00:00:00 2001 From: Tuan-Dat Tran Date: Sat, 26 Apr 2025 00:00:51 +0200 Subject: [PATCH 6/8] feat(docker): Added healthcheck Signed-off-by: Tuan-Dat Tran --- roles/docker_host/templates/compose.yaml.j2 | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/roles/docker_host/templates/compose.yaml.j2 b/roles/docker_host/templates/compose.yaml.j2 index 9648015..2a7df12 100644 --- a/roles/docker_host/templates/compose.yaml.j2 +++ b/roles/docker_host/templates/compose.yaml.j2 @@ -21,6 +21,27 @@ services: {% endfor %} {% endif %} {% endif %} +{% if service.ports is defined and service.ports is iterable %} +{% set first_http_port = service.ports | default([]) | selectattr('name', 'defined') | selectattr('name', 'search', 'http') | first %} +{% set chosen_http_port_value = none %} +{% if first_http_port is not none %} +{% if first_http_port.internal is defined and first_http_port.internal == 'proxy_only' %} +{% if first_http_port.external is defined %} +{% set chosen_http_port_value = first_http_port.external %} +{% endif %} +{% else %} +{% set chosen_http_port_value = first_http_port.internal %} +{% endif %} +{% if chosen_http_port_value is defined %} + healthcheck: + test: ["CMD-SHELL", "wget --quiet --spider --timeout=5 http://localhost:{{ chosen_http_port_value }}/ || exit 1"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 20s +{% endif %} +{% endif %} +{% endif %} {% if service.cap_add is defined and service.cap_add is iterable %} cap_add: {% for cap in service.cap_add %} -- 2.49.1 From f2ea03bc012650e32dedba30e39d4b12a807c20c Mon Sep 17 00:00:00 2001 From: Tuan-Dat Tran Date: Sat, 26 Apr 2025 21:58:58 +0200 Subject: [PATCH 7/8] feat(proxmox): automatic vm creation Signed-off-by: Tuan-Dat Tran --- group_vars/proxmox/secrets_vm.yml | 8 ++ group_vars/proxmox/vars.yml | 13 +-- host_vars/aya01.yml | 18 ++-- host_vars/docker-host00.yml | 7 +- host_vars/docker-host01.yml | 8 +- host_vars/docker-host02.yml | 7 +- host_vars/docker-lb.yml | 7 +- host_vars/inko.yml | 18 ++-- host_vars/lulu.yml | 18 ++-- playbooks/proxmox.yml | 5 +- production.ini | 3 + .../templates/postgres_exporter.service.j2 | 2 +- roles/proxmox/tasks/00_setup_machines.yml | 8 ++ roles/proxmox/tasks/01_setup_localhost.yml | 7 ++ roles/proxmox/tasks/01_setup_user.yml | 0 roles/proxmox/tasks/05_setup_node.yml | 7 ++ roles/proxmox/tasks/10_create_secrets.yml | 2 +- .../proxmox/tasks/40_prepare_vm_creation.yml | 6 ++ roles/proxmox/tasks/42_download_isos.yml | 12 +++ roles/proxmox/tasks/50_create_vms.yml | 12 ++- roles/proxmox/tasks/54_destroy_vm.yml | 30 ++++++ roles/proxmox/tasks/55_create_vm.yml | 92 +++++++++++++++---- roles/proxmox/tasks/60_create_container.yml | 2 +- roles/proxmox/tasks/90-download-image.yml | 6 -- roles/proxmox/tasks/main.yml | 12 ++- roles/proxmox/vars/main.yml | 25 ++++- roles/reverse_proxy/templates/Caddyfile.j2 | 2 +- 27 files changed, 247 insertions(+), 90 deletions(-) create mode 100644 group_vars/proxmox/secrets_vm.yml create mode 100644 roles/proxmox/tasks/00_setup_machines.yml create mode 100644 roles/proxmox/tasks/01_setup_localhost.yml delete mode 100644 roles/proxmox/tasks/01_setup_user.yml create mode 100644 roles/proxmox/tasks/05_setup_node.yml create mode 100644 roles/proxmox/tasks/40_prepare_vm_creation.yml create mode 100644 roles/proxmox/tasks/42_download_isos.yml create mode 100644 roles/proxmox/tasks/54_destroy_vm.yml delete mode 100644 roles/proxmox/tasks/90-download-image.yml diff --git a/group_vars/proxmox/secrets_vm.yml b/group_vars/proxmox/secrets_vm.yml new file mode 100644 index 0000000..8c1eb5f --- /dev/null +++ b/group_vars/proxmox/secrets_vm.yml @@ -0,0 +1,8 @@ +$ANSIBLE_VAULT;1.1;AES256 +33333937646463646566653162383830616434336437623065363665323739633331346266333763 +3364663264306665626465666133666161626333323462650a353366303331303837316133326135 +33623862333036633438343538633161643333663632303362396438316638626338663935353337 +3532323337663864640a333765653732393937396561373361393762386565353266343537306161 +62303539333837666365323630303836373065343437663433616664376432313135636266663764 +36616132383330656165656264346231323039626131646432323935306233643866366439313962 +353837396234643739346662316239356134 diff --git a/group_vars/proxmox/vars.yml b/group_vars/proxmox/vars.yml index 9564961..c9f4766 100644 --- a/group_vars/proxmox/vars.yml +++ b/group_vars/proxmox/vars.yml @@ -2,21 +2,18 @@ proxmox_api_user: root proxmox_api_host: 192.168.20.12 proxmox_api_password: "{{ vault.pve.aya01.root.sudo }}" -proxmox_vms: +vms: - name: "test-vm-00" node: "inko" vmid: 950 cores: 2 - cpu: "x86-64-v2-AES" memory: 8192 # in MiB net: net0: "virtio,bridge=vmbr0,firewall=1" - scsi: - scsi0: "proxmox:64,format=qcow2" - scsihw: "virtio-scsi-single" - ostype: "l26" - sshkeys: "{{ pubkey }}" + boot_image: "{{ proxmox_cloud_init_images.ubuntu.name }}" ciuser: "{{ user }}" + sshkeys: "{{ pubkey }}" + disk_size: 32 # in Gb -proxmox_lxcs: +lxcs: - name: "test-lxc-00" diff --git a/host_vars/aya01.yml b/host_vars/aya01.yml index 2b172a1..2443694 100644 --- a/host_vars/aya01.yml +++ b/host_vars/aya01.yml @@ -1,10 +1,10 @@ --- -ansible_user: "root" -ansible_host: 192.168.20.12 -ansible_port: 22 -ansible_ssh_private_key_file: "{{ pk_path }}" -ansible_become_pass: "{{ vault.pve.aya01.root.sudo }}" - -host: - hostname: "aya01" - ip: "{{ ansible_host }}" +# 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 }}" diff --git a/host_vars/docker-host00.yml b/host_vars/docker-host00.yml index 74135f1..3a6f8c2 100644 --- a/host_vars/docker-host00.yml +++ b/host_vars/docker-host00.yml @@ -5,7 +5,6 @@ # ansible_port: 22 # ansible_ssh_private_key_file: "{{ pk_path }}" ansible_become_pass: "{{ vault.docker.host00.sudo }}" - -host: - hostname: "docker-host00" - ip: "192.168.20.34" +# host: +# hostname: "docker-host00" +# ip: "192.168.20.34" diff --git a/host_vars/docker-host01.yml b/host_vars/docker-host01.yml index 19c5d36..f8d506a 100644 --- a/host_vars/docker-host01.yml +++ b/host_vars/docker-host01.yml @@ -5,7 +5,7 @@ # ansible_port: 22 # ansible_ssh_private_key_file: "{{ pk_path }}" ansible_become_pass: "{{ vault.docker.host01.sudo }}" - -host: - hostname: "docker-host01" - ip: "192.168.20.35" +# +# host: +# hostname: "docker-host01" +# ip: "192.168.20.35" diff --git a/host_vars/docker-host02.yml b/host_vars/docker-host02.yml index 589ac16..c51ad77 100644 --- a/host_vars/docker-host02.yml +++ b/host_vars/docker-host02.yml @@ -5,7 +5,6 @@ # ansible_port: 22 # ansible_ssh_private_key_file: "{{ pk_path }}" ansible_become_pass: "{{ vault.docker.host02.sudo }}" - -host: - hostname: "docker-host02" - ip: "192.168.20.36" +# host: +# hostname: "docker-host02" +# ip: "192.168.20.36" diff --git a/host_vars/docker-lb.yml b/host_vars/docker-lb.yml index 7024e36..b3fd90b 100644 --- a/host_vars/docker-lb.yml +++ b/host_vars/docker-lb.yml @@ -4,7 +4,6 @@ # ansible_port: 22 # ansible_ssh_private_key_file: "{{ pk_path }}" ansible_become_pass: "{{ vault.docker.lb.sudo }}" - -host: - hostname: "docker-lb" - ip: "192.168.20.37" +# host: +# hostname: "docker-lb" +# ip: "192.168.20.37" diff --git a/host_vars/inko.yml b/host_vars/inko.yml index 32327a4..cc39169 100644 --- a/host_vars/inko.yml +++ b/host_vars/inko.yml @@ -1,10 +1,10 @@ --- -ansible_user: "root" -ansible_host: 192.168.20.14 -ansible_port: 22 -ansible_ssh_private_key_file: "{{ pk_path }}" -ansible_become_pass: "{{ vault.pve.inko.root.sudo }}" - -host: - hostname: "inko" - ip: "{{ ansible_host }}" +# 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 }}" diff --git a/host_vars/lulu.yml b/host_vars/lulu.yml index e490d2f..7802e91 100644 --- a/host_vars/lulu.yml +++ b/host_vars/lulu.yml @@ -1,10 +1,10 @@ --- -ansible_user: "root" -ansible_host: 192.168.20.28 -ansible_port: 22 -ansible_ssh_private_key_file: "{{ pk_path }}" -ansible_become_pass: "{{ vault.pve.lulu.root.sudo }}" - -host: - hostname: "lulu" - ip: "{{ ansible_host }}" +# 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 }}" diff --git a/playbooks/proxmox.yml b/playbooks/proxmox.yml index be440f8..f3d9fff 100644 --- a/playbooks/proxmox.yml +++ b/playbooks/proxmox.yml @@ -4,9 +4,10 @@ gather_facts: true vars_files: - secrets.yml + vars: + is_localhost: "{{ inventory_hostname == '127.0.0.1' }}" + is_proxmox_node: "{{ 'proxmox_nodes' in group_names }}" roles: - role: proxmox tags: - proxmox - vars: - action: provision diff --git a/production.ini b/production.ini index deb6855..f908486 100644 --- a/production.ini +++ b/production.ini @@ -2,6 +2,9 @@ 127.0.0.1 ansible_connection=local [proxmox:children] +proxmox_nodes + +[proxmox_nodes] aya01 lulu inko diff --git a/roles/postgres_exporter/templates/postgres_exporter.service.j2 b/roles/postgres_exporter/templates/postgres_exporter.service.j2 index 1c50b77..b4a2f99 100644 --- a/roles/postgres_exporter/templates/postgres_exporter.service.j2 +++ b/roles/postgres_exporter/templates/postgres_exporter.service.j2 @@ -4,7 +4,7 @@ Description=PostgresExporter [Service] TimeoutStartSec=0 User={{ bin_name }} -ExecStart={{ bin_path }} --web.listen-address={{ host.ip }}:{{ bind_port }} {{ options }} +ExecStart={{ bin_path }} --web.listen-address={{ ansible_host }}:{{ bind_port }} {{ options }} Environment="DATA_SOURCE_URI=localhost:5432/postgres?sslmode=disable" Environment="DATA_SOURCE_USER={{ db.user }}" Environment="DATA_SOURCE_PASS={{ db.password }}" diff --git a/roles/proxmox/tasks/00_setup_machines.yml b/roles/proxmox/tasks/00_setup_machines.yml new file mode 100644 index 0000000..ec01b4e --- /dev/null +++ b/roles/proxmox/tasks/00_setup_machines.yml @@ -0,0 +1,8 @@ +--- +- name: Prepare Localhost + ansible.builtin.include_tasks: ./01_setup_localhost.yml + when: is_localhost + +- name: Prepare Localhost + ansible.builtin.include_tasks: ./05_setup_node.yml + when: is_proxmox_node diff --git a/roles/proxmox/tasks/01_setup_localhost.yml b/roles/proxmox/tasks/01_setup_localhost.yml new file mode 100644 index 0000000..17bfc43 --- /dev/null +++ b/roles/proxmox/tasks/01_setup_localhost.yml @@ -0,0 +1,7 @@ +--- +- name: Install dependencies + ansible.builtin.apt: + name: "{{ item }}" + update_cache: true + state: present + loop: "{{ proxmox_localhost_dependencies }}" diff --git a/roles/proxmox/tasks/01_setup_user.yml b/roles/proxmox/tasks/01_setup_user.yml deleted file mode 100644 index e69de29..0000000 diff --git a/roles/proxmox/tasks/05_setup_node.yml b/roles/proxmox/tasks/05_setup_node.yml new file mode 100644 index 0000000..f2d1fed --- /dev/null +++ b/roles/proxmox/tasks/05_setup_node.yml @@ -0,0 +1,7 @@ +--- +- name: Install dependencies + ansible.builtin.apt: + name: "{{ item }}" + update_cache: true + state: present + loop: "{{ proxmox_node_dependencies }}" diff --git a/roles/proxmox/tasks/10_create_secrets.yml b/roles/proxmox/tasks/10_create_secrets.yml index 4feec24..39f48de 100644 --- a/roles/proxmox/tasks/10_create_secrets.yml +++ b/roles/proxmox/tasks/10_create_secrets.yml @@ -23,7 +23,7 @@ - name: Update Vault data ansible.builtin.include_tasks: 15_create_secret.yml - loop: "{{ proxmox_vms | map(attribute='name') }}" + loop: "{{ vms | map(attribute='name') }}" loop_control: loop_var: "vm_name" diff --git a/roles/proxmox/tasks/40_prepare_vm_creation.yml b/roles/proxmox/tasks/40_prepare_vm_creation.yml new file mode 100644 index 0000000..ea03d8f --- /dev/null +++ b/roles/proxmox/tasks/40_prepare_vm_creation.yml @@ -0,0 +1,6 @@ +--- +- name: Download Cloud Init Isos + ansible.builtin.include_tasks: 42_download_isos.yml + loop: "{{ proxmox_cloud_init_images | dict2items | map(attribute='value') }}" + loop_control: + loop_var: distro diff --git a/roles/proxmox/tasks/42_download_isos.yml b/roles/proxmox/tasks/42_download_isos.yml new file mode 100644 index 0000000..428f63d --- /dev/null +++ b/roles/proxmox/tasks/42_download_isos.yml @@ -0,0 +1,12 @@ +--- +- name: Check if file exists + ansible.builtin.stat: + path: "{{ proxmox_dirs.isos }}/{{ distro.name }}" + register: image_stat + +- name: Download image if missing + ansible.builtin.get_url: + url: "{{ distro.url }}" + dest: "{{ proxmox_dirs.isos }}/{{ distro.name }}" + mode: "0644" + when: not image_stat.stat.exists diff --git a/roles/proxmox/tasks/50_create_vms.yml b/roles/proxmox/tasks/50_create_vms.yml index c407f40..d052154 100644 --- a/roles/proxmox/tasks/50_create_vms.yml +++ b/roles/proxmox/tasks/50_create_vms.yml @@ -4,8 +4,14 @@ file: "{{ proxmox_vault_file }}" name: vm_secrets -- name: Create vms - ansible.builtin.include_tasks: 55_create_vm.yml - loop: "{{ proxmox_vms }}" +- name: Destroy vms (Only during rapid testing) + ansible.builtin.include_tasks: 54_destroy_vm.yml + loop: "{{ vms }}" + loop_control: + loop_var: "vm" + +- name: Create vms + ansible.builtin.include_tasks: 55_create_vm.yml + loop: "{{ vms }}" loop_control: loop_var: "vm" diff --git a/roles/proxmox/tasks/54_destroy_vm.yml b/roles/proxmox/tasks/54_destroy_vm.yml new file mode 100644 index 0000000..4b14aea --- /dev/null +++ b/roles/proxmox/tasks/54_destroy_vm.yml @@ -0,0 +1,30 @@ +--- +- name: Gather info about VM + community.general.proxmox_vm_info: + api_user: root@pam + api_password: "{{ vault.pve.aya01.root.sudo }}" + api_host: "192.168.20.12" + vmid: "{{ vm.vmid }}" + register: vm_info + +- name: Stop VM + community.general.proxmox_kvm: + api_user: root@pam + api_password: "{{ vault.pve.aya01.root.sudo }}" + api_host: "192.168.20.12" + node: "{{ vm.node }}" + vmid: "{{ vm.vmid }}" + state: stopped + force: true + when: vm_info.proxmox_vms | length > 0 + +- name: Destroy VM + community.general.proxmox_kvm: + api_user: root@pam + api_password: "{{ vault.pve.aya01.root.sudo }}" + api_host: "192.168.20.12" + node: "{{ vm.node }}" + vmid: "{{ vm.vmid }}" + state: absent + force: true + when: vm_info.proxmox_vms | length > 0 diff --git a/roles/proxmox/tasks/55_create_vm.yml b/roles/proxmox/tasks/55_create_vm.yml index cff235d..76d861d 100644 --- a/roles/proxmox/tasks/55_create_vm.yml +++ b/roles/proxmox/tasks/55_create_vm.yml @@ -1,34 +1,94 @@ +--- - name: Create VM community.general.proxmox_kvm: api_user: root@pam api_password: "{{ vault.pve.aya01.root.sudo }}" api_host: "192.168.20.12" + agent: true name: "{{ vm.name }}" vmid: "{{ vm.vmid }}" node: "{{ vm.node }}" - cpu: "{{ vm.cpu }}" cores: "{{ vm.cores }}" memory: "{{ vm.memory }}" net: "{{ vm.net }}" - scsi: "{{ vm.scsi }}" - scsihw: "{{ vm.scsihw }}" - ostype: "{{ vm.ostype }}" - sshkeys: "{{ vm.sshkeys }}" + scsihw: "virtio-scsi-pci" + ostype: "l26" tags: "{{ proxmox_tags }}" + description: "Created via Ansible with cloud-init" + boot: "order=scsi0" + cpu: "x86-64-v2-AES" ciuser: "{{ vm.ciuser }}" cipassword: "{{ vm_secrets[proxmox_secrets_prefix + '_' + vm.name.replace('-', '_')] }}" - ide: - ide2: "proxmox:cloudinit,format=qcow2" - register: temp + ipconfig: + ipconfig0: "ip=dhcp" + sshkeys: "{{ vm.sshkeys }}" + register: proxmox_deploy_info -- name: Debug temp - ansible.builtin.debug: - msg: "{{ temp }}" - -- name: Set mac +- name: Get MAC Address of new machine ansible.builtin.set_fact: - mac: "{{ temp.mac }}" + mac_address: "{{ proxmox_deploy_info.mac.net0 }}" -- name: debug mac +- name: Import disk + ansible.builtin.shell: | + qm importdisk {{ vm.vmid }} {{ proxmox_dirs.isos }}/{{ vm.boot_image }} {{ proxmox_storage }} + delegate_to: "{{ vm.node }}" + +- name: Attach disk and cloud-init + ansible.builtin.shell: | + qm set {{ vm.vmid }} --scsi0 {{ proxmox_storage }}:{{ vm.vmid }}/vm-{{ vm.vmid }}-disk-0.raw --ide2 {{ proxmox_storage }}:cloudinit --boot order=scsi0 + delegate_to: "{{ vm.node }}" + +- name: Resize scsi0 disk if needed + ansible.builtin.shell: | + qm resize {{ vm.vmid }} scsi0 {{ vm.disk_size }}G + delegate_to: "{{ vm.node }}" + +- name: Start VM + community.general.proxmox_kvm: + api_user: root@pam + api_password: "{{ vault.pve.aya01.root.sudo }}" + api_host: "192.168.20.12" + node: "{{ vm.node }}" + vmid: "{{ vm.vmid }}" + state: started + +- name: Wait for VM to appear on network + ansible.builtin.shell: | + nmap -sn -n -PR 192.168.20.0/24 | grep -B2 "{{ mac_address }}" | grep "Nmap scan report for" + register: vm_nmap_scan + retries: 30 + delay: 5 + until: vm_nmap_scan.stdout != "" + delegate_to: "{{ vm.node }}" + +- name: Extract the IP address from Nmap output + ansible.builtin.set_fact: + vm_found_ip: "{{ vm_nmap_scan.stdout | regex_search('Nmap scan report for ([0-9\\.]+)', '\\1') | first }}" + +- name: Debug IP address ansible.builtin.debug: - msg: "{{ mac }}" + msg: "Found VM IP address: {{ vm_found_ip }}" + +- name: Define SSH config block + ansible.builtin.set_fact: + ssh_entry: | + Host {{ vm.name }} + HostName {{ vm_found_ip }} + Port 22 + User tudattr + IdentityFile /media/veracrypt1/genesis + ProxyJump {{ vm.node }} + +- name: Append new VM to SSH config + ansible.builtin.blockinfile: + path: "{{ ansible_env.HOME }}/.ssh/config_homelab" + marker: "# {mark} HOMELAB VMS BLOCK" + block: | + {{ ssh_entry }} + +- name: Add the new VM to the proxmox_nodes group in production.ini + ansible.builtin.lineinfile: + path: "../inventory.ini" + line: "{{ proxmox_inventory_entry }}" + insertafter: "[proxmox_nodes]" + state: present diff --git a/roles/proxmox/tasks/60_create_container.yml b/roles/proxmox/tasks/60_create_container.yml index b9d4168..e1a29a0 100644 --- a/roles/proxmox/tasks/60_create_container.yml +++ b/roles/proxmox/tasks/60_create_container.yml @@ -6,6 +6,6 @@ - name: Create vms ansible.builtin.include_tasks: 65_create_container.yml - loop: "{{ proxmox_lxcs }}" + loop: "{{ lxcs }}" loop_control: loop_var: "container" diff --git a/roles/proxmox/tasks/90-download-image.yml b/roles/proxmox/tasks/90-download-image.yml deleted file mode 100644 index f6222c6..0000000 --- a/roles/proxmox/tasks/90-download-image.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Download Debian Image - ansible.builtin.get_url: - url: "{{ proxmox_debian_image_url }}" - dest: "{{ proxmox_image_path }}" - mode: "0644" diff --git a/roles/proxmox/tasks/main.yml b/roles/proxmox/tasks/main.yml index b7e78c8..d0b3422 100644 --- a/roles/proxmox/tasks/main.yml +++ b/roles/proxmox/tasks/main.yml @@ -1,12 +1,18 @@ --- -- name: Setup user - ansible.builtin.include_tasks: 01_setup_user.yml +- name: Prepare Machines + ansible.builtin.include_tasks: 00_setup_machines.yml - name: Create VM vault ansible.builtin.include_tasks: 10_create_secrets.yml + when: is_localhost + +- name: Prime node for VM + ansible.builtin.include_tasks: 40_prepare_vm_creation.yml + when: is_proxmox_node - name: Create VMs ansible.builtin.include_tasks: 50_create_vms.yml - + when: is_localhost - name: Create LXC containers ansible.builtin.include_tasks: 60_create_containers.yml + when: is_localhost diff --git a/roles/proxmox/vars/main.yml b/roles/proxmox/vars/main.yml index 1587e21..17ce0bc 100644 --- a/roles/proxmox/vars/main.yml +++ b/roles/proxmox/vars/main.yml @@ -1,10 +1,25 @@ -author: tuan-dat.tran@tudattr.dev -creator: ansible +proxmox_author: tuan-dat.tran@tudattr.dev +proxmox_creator: ansible + +proxmox_storage: proxmox proxmox_vault_file: ../group_vars/proxmox/secrets_vm.yml proxmox_secrets_prefix: secrets_vm -proxmox_debian_image_url: https://cdimage.debian.org/images/cloud/bookworm/20250316-2053/debian-12-genericcloud-amd64-20250316-2053.qcow2 -proxmox_image_path: /opt/template/iso/ +proxmox_cloud_init_images: + debian: + name: debian-12-genericcloud-amd64.qcow2 + url: https://cdimage.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2 + ubuntu: + name: noble-server-cloudimg-amd64.img + url: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img +proxmox_dirs: + isos: /opt/proxmox/template/iso/ proxmox_tags: - - "{{ creator }}" + - "{{ proxmox_creator }}" + +proxmox_node_dependencies: + - libguestfs-tools + - nmap + +proxmox_localhost_dependencies: [] diff --git a/roles/reverse_proxy/templates/Caddyfile.j2 b/roles/reverse_proxy/templates/Caddyfile.j2 index 1c52c80..9c7faaa 100644 --- a/roles/reverse_proxy/templates/Caddyfile.j2 +++ b/roles/reverse_proxy/templates/Caddyfile.j2 @@ -10,7 +10,7 @@ {% if http_port %} {{ service.name }}.{{ domain }} { {% for vm in service.vm %} - reverse_proxy {{ hostvars[vm].host.ip }}:{{ http_port[0] }} + reverse_proxy {{ hostvars[vm].ansible_host }}:{{ http_port[0] }} {% endfor %} log { output file /var/log/caddy/{{ service.name }}.log -- 2.49.1 From 591342f58057d5f8ffb1da22e3fe45e226c9736a Mon Sep 17 00:00:00 2001 From: Tuan-Dat Tran Date: Sat, 26 Apr 2025 23:34:42 +0200 Subject: [PATCH 8/8] feat(proxmox): refactor vm provisioning and add pci passthrough config Signed-off-by: Tuan-Dat Tran --- group_vars/proxmox/secrets_vm.yml | 14 ++-- production.ini | 3 - roles/docker_host/tasks/setup.yml | 7 +- roles/docker_host/vars/main.yml | 2 + roles/proxmox/handlers/node.yml | 6 ++ .../tasks/06_hardware_acceleration.yml | 25 +++++++ roles/proxmox/tasks/55_create_vm.yml | 71 +----------------- roles/proxmox/tasks/56_provision_new_vm.yml | 72 +++++++++++++++++++ ...container.yml => 60_create_containers.yml} | 0 ...containers.yml => 65_create_container.yml} | 0 roles/proxmox/vars/main.yml | 1 + 11 files changed, 119 insertions(+), 82 deletions(-) create mode 100644 roles/docker_host/vars/main.yml create mode 100644 roles/proxmox/handlers/node.yml create mode 100644 roles/proxmox/tasks/06_hardware_acceleration.yml create mode 100644 roles/proxmox/tasks/56_provision_new_vm.yml rename roles/proxmox/tasks/{60_create_container.yml => 60_create_containers.yml} (100%) rename roles/proxmox/tasks/{65_create_containers.yml => 65_create_container.yml} (100%) diff --git a/group_vars/proxmox/secrets_vm.yml b/group_vars/proxmox/secrets_vm.yml index 8c1eb5f..5908811 100644 --- a/group_vars/proxmox/secrets_vm.yml +++ b/group_vars/proxmox/secrets_vm.yml @@ -1,8 +1,8 @@ $ANSIBLE_VAULT;1.1;AES256 -33333937646463646566653162383830616434336437623065363665323739633331346266333763 -3364663264306665626465666133666161626333323462650a353366303331303837316133326135 -33623862333036633438343538633161643333663632303362396438316638626338663935353337 -3532323337663864640a333765653732393937396561373361393762386565353266343537306161 -62303539333837666365323630303836373065343437663433616664376432313135636266663764 -36616132383330656165656264346231323039626131646432323935306233643866366439313962 -353837396234643739346662316239356134 +62653436363035633565383636383931353765663136646362366439306635306430313763323331 +3533346430316564356463613664366261336139636331320a636532633836303161396238663163 +39643765613162346261643662333633323133373830313365326534626161326235363038383462 +6531643136646464610a383532316434383264326665613436623331333730633035316530663031 +63343539393062383065396638363064613932363164346632366134333637343337353033346131 +30613162303536313366656137306165303032636366376362656137343235313838356463306532 +653164653834613431633563633739313936 diff --git a/production.ini b/production.ini index f908486..78dc966 100644 --- a/production.ini +++ b/production.ini @@ -56,6 +56,3 @@ docker-host[00:01] [docker_lb] docker-lb - -[vm:vars] -ansible_ssh_common_args='-o ProxyCommand="ssh -p 22 -W %h:%p -q aya01"' diff --git a/roles/docker_host/tasks/setup.yml b/roles/docker_host/tasks/setup.yml index 279e009..5a26220 100644 --- a/roles/docker_host/tasks/setup.yml +++ b/roles/docker_host/tasks/setup.yml @@ -1,9 +1,8 @@ --- -- name: Enable HW accelerate for VM +- name: Setup VM Packages ansible.builtin.apt: name: "{{ item }}" state: present - loop: - - firmware-misc-nonfree - - nfs-common + update_cache: true + loop: "{{ docker_host_package_common_dependencies }}" become: true diff --git a/roles/docker_host/vars/main.yml b/roles/docker_host/vars/main.yml new file mode 100644 index 0000000..259b6c6 --- /dev/null +++ b/roles/docker_host/vars/main.yml @@ -0,0 +1,2 @@ +docker_host_package_common_dependencies: + - nfs-common diff --git a/roles/proxmox/handlers/node.yml b/roles/proxmox/handlers/node.yml new file mode 100644 index 0000000..b7222ef --- /dev/null +++ b/roles/proxmox/handlers/node.yml @@ -0,0 +1,6 @@ +--- +- name: Reboot Node + ansible.builtin.reboot: + connect_timeout: 5 + reboot_timeout: 600 + test_command: whoami diff --git a/roles/proxmox/tasks/06_hardware_acceleration.yml b/roles/proxmox/tasks/06_hardware_acceleration.yml new file mode 100644 index 0000000..d2052b0 --- /dev/null +++ b/roles/proxmox/tasks/06_hardware_acceleration.yml @@ -0,0 +1,25 @@ +--- +- name: Set GRUB_CMDLINE_LINUX_DEFAULT for PCI passthrough + ansible.builtin.lineinfile: + path: /etc/default/grub + regexp: "^GRUB_CMDLINE_LINUX_DEFAULT=" + line: 'GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction initcall_blacklist=sysfb_init video=simplefb:off video=vesafb:off video=efifb:off video=vesa:off disable_vga=1 vfio_iommu_type1.allow_unsafe_interrupts=1 kvm.ignore_msrs=1 modprobe.blacklist=radeon,nouveau,nvidia,nvidiafb,nvidia-gpu,snd_hda_intel,snd_hda_codec_hdmi,i915"' + backup: true + # notify: + # - Reboot Node + +- name: Ensure VFIO modules are listed in /etc/modules + ansible.builtin.blockinfile: + path: /etc/modules + marker: "# {mark} VFIO Modules" + block: | + vfio + vfio_iommu_type1 + vfio_pci + vfio_virqfd + create: true + +- name: Update initramfs + ansible.builtin.command: update-initramfs -u -k all + args: + warn: false diff --git a/roles/proxmox/tasks/55_create_vm.yml b/roles/proxmox/tasks/55_create_vm.yml index 76d861d..8bd4883 100644 --- a/roles/proxmox/tasks/55_create_vm.yml +++ b/roles/proxmox/tasks/55_create_vm.yml @@ -24,71 +24,6 @@ sshkeys: "{{ vm.sshkeys }}" register: proxmox_deploy_info -- name: Get MAC Address of new machine - ansible.builtin.set_fact: - mac_address: "{{ proxmox_deploy_info.mac.net0 }}" - -- name: Import disk - ansible.builtin.shell: | - qm importdisk {{ vm.vmid }} {{ proxmox_dirs.isos }}/{{ vm.boot_image }} {{ proxmox_storage }} - delegate_to: "{{ vm.node }}" - -- name: Attach disk and cloud-init - ansible.builtin.shell: | - qm set {{ vm.vmid }} --scsi0 {{ proxmox_storage }}:{{ vm.vmid }}/vm-{{ vm.vmid }}-disk-0.raw --ide2 {{ proxmox_storage }}:cloudinit --boot order=scsi0 - delegate_to: "{{ vm.node }}" - -- name: Resize scsi0 disk if needed - ansible.builtin.shell: | - qm resize {{ vm.vmid }} scsi0 {{ vm.disk_size }}G - delegate_to: "{{ vm.node }}" - -- name: Start VM - community.general.proxmox_kvm: - api_user: root@pam - api_password: "{{ vault.pve.aya01.root.sudo }}" - api_host: "192.168.20.12" - node: "{{ vm.node }}" - vmid: "{{ vm.vmid }}" - state: started - -- name: Wait for VM to appear on network - ansible.builtin.shell: | - nmap -sn -n -PR 192.168.20.0/24 | grep -B2 "{{ mac_address }}" | grep "Nmap scan report for" - register: vm_nmap_scan - retries: 30 - delay: 5 - until: vm_nmap_scan.stdout != "" - delegate_to: "{{ vm.node }}" - -- name: Extract the IP address from Nmap output - ansible.builtin.set_fact: - vm_found_ip: "{{ vm_nmap_scan.stdout | regex_search('Nmap scan report for ([0-9\\.]+)', '\\1') | first }}" - -- name: Debug IP address - ansible.builtin.debug: - msg: "Found VM IP address: {{ vm_found_ip }}" - -- name: Define SSH config block - ansible.builtin.set_fact: - ssh_entry: | - Host {{ vm.name }} - HostName {{ vm_found_ip }} - Port 22 - User tudattr - IdentityFile /media/veracrypt1/genesis - ProxyJump {{ vm.node }} - -- name: Append new VM to SSH config - ansible.builtin.blockinfile: - path: "{{ ansible_env.HOME }}/.ssh/config_homelab" - marker: "# {mark} HOMELAB VMS BLOCK" - block: | - {{ ssh_entry }} - -- name: Add the new VM to the proxmox_nodes group in production.ini - ansible.builtin.lineinfile: - path: "../inventory.ini" - line: "{{ proxmox_inventory_entry }}" - insertafter: "[proxmox_nodes]" - state: present +- name: Provision created VM + ansible.builtin.include_tasks: 56_provision_new_vm.yml + when: proxmox_deploy_info.changed diff --git a/roles/proxmox/tasks/56_provision_new_vm.yml b/roles/proxmox/tasks/56_provision_new_vm.yml new file mode 100644 index 0000000..934ca52 --- /dev/null +++ b/roles/proxmox/tasks/56_provision_new_vm.yml @@ -0,0 +1,72 @@ +--- +- name: Debug proxmox_deploy_info + ansible.builtin.debug: + msg: "{{ proxmox_deploy_info }}" + +- name: Get MAC Address of new machine + ansible.builtin.set_fact: + mac_address: "{{ proxmox_deploy_info.mac.net0 }}" + +- name: Import disk + ansible.builtin.shell: | + qm importdisk {{ vm.vmid }} {{ proxmox_dirs.isos }}/{{ vm.boot_image }} {{ proxmox_storage }} + delegate_to: "{{ vm.node }}" + when: proxmox_deploy_info.changed + +- name: Attach disk and cloud-init + ansible.builtin.shell: | + qm set {{ vm.vmid }} --scsi0 {{ proxmox_storage }}:{{ vm.vmid }}/vm-{{ vm.vmid }}-disk-0.raw --ide2 {{ proxmox_storage }}:cloudinit --boot order=scsi0 + delegate_to: "{{ vm.node }}" + +- name: Resize scsi0 disk if needed + ansible.builtin.shell: | + qm resize {{ vm.vmid }} scsi0 {{ vm.disk_size }}G + delegate_to: "{{ vm.node }}" + +- name: Start VM + community.general.proxmox_kvm: + api_user: root@pam + api_password: "{{ vault.pve.aya01.root.sudo }}" + api_host: "192.168.20.12" + node: "{{ vm.node }}" + vmid: "{{ vm.vmid }}" + state: started + +- name: Wait for VM to appear on network + ansible.builtin.shell: | + nmap -sn -n -PR 192.168.20.0/24 | grep -B2 "{{ mac_address }}" | grep "Nmap scan report for" + register: vm_nmap_scan + retries: 30 + delay: 5 + until: vm_nmap_scan.stdout != "" + delegate_to: "{{ vm.node }}" + +- name: Extract the IP address from Nmap output + ansible.builtin.set_fact: + vm_found_ip: "{{ vm_nmap_scan.stdout | regex_search('Nmap scan report for ([0-9\\.]+)', '\\1') | first }}" + +- name: Define SSH config block + ansible.builtin.set_fact: + ssh_entry: | + Host {{ vm.name }} + HostName {{ vm_found_ip }} + Port 22 + User tudattr + IdentityFile /media/veracrypt1/genesis + ProxyJump {{ vm.node }} + +- name: Append new VM to SSH config + ansible.builtin.blockinfile: + path: "{{ ansible_env.HOME }}/.ssh/config_homelab" + marker: "# {mark} HOMELAB VMS BLOCK" + block: | + {{ ssh_entry }} + +- name: Add VM to homelab_vms group in production.ini + ansible.builtin.lineinfile: + path: "{{ inventory_file }}" + line: "{{ vm.name }}" + insertafter: '^\[vms\]' + create: true + state: present + delegate_to: localhost diff --git a/roles/proxmox/tasks/60_create_container.yml b/roles/proxmox/tasks/60_create_containers.yml similarity index 100% rename from roles/proxmox/tasks/60_create_container.yml rename to roles/proxmox/tasks/60_create_containers.yml diff --git a/roles/proxmox/tasks/65_create_containers.yml b/roles/proxmox/tasks/65_create_container.yml similarity index 100% rename from roles/proxmox/tasks/65_create_containers.yml rename to roles/proxmox/tasks/65_create_container.yml diff --git a/roles/proxmox/vars/main.yml b/roles/proxmox/vars/main.yml index 17ce0bc..c48123b 100644 --- a/roles/proxmox/vars/main.yml +++ b/roles/proxmox/vars/main.yml @@ -21,5 +21,6 @@ proxmox_tags: proxmox_node_dependencies: - libguestfs-tools - nmap + - firmware-misc-nonfree proxmox_localhost_dependencies: [] -- 2.49.1