2023-06-11 19:25:36 +02:00
# Proxmox Deploy
[![Build Status ](https://drone.broillet.ch/api/badges/mathieu/ProxmoxDeploy/status.svg )](https://drone.broillet.ch/mathieu/ProxmoxDeploy)
2023-06-12 11:01:05 +02:00
![Logo ](./.git-images/logo.png )
2023-06-11 19:25:36 +02:00
## Description
Proxmox Deploy is a little script to manage my HomeLab with JSON file.
## Why?
As my homelab was growing I realised that it was harder and harder to keep everything in sync and up to date.
So I decided to create a script to manage my Proxmox homelab.
2023-06-14 15:52:30 +02:00
# How it works
The concept is simple, you have a Git repository with a the following structure:
```
.
├── config.json
├── lxc
│ ├── < id >
│ │ ├── config.json
│ │ ├── < your files >
│ │ └── < your folders >
│ └── < id >
│ ├── ...
│── qemu
│ ├── < id >
│ │ ├── config.json
│ │ ├── < your files >
│ │ └── < your folders >
│ └── < id >
│ ├── ...
│── scripts
│ ├── < your scripts >
│ └── ...
```
*See below for more information about the structure and differents files*
2023-06-11 19:25:36 +02:00
2023-06-14 15:52:30 +02:00
PDJ (Proxmox Deploy JSON) is a program that will read that repository files and execute the necessary commands to create/update your LXC/VM.
Now ideally you have some sort of Git actions like Drone/GitHub(/Gitea) Actions to run PDJ automatically when you push a change, which will result in your homelab being updated almost instantly.
2023-06-11 22:10:22 +02:00
2023-06-14 15:52:30 +02:00
If you don't, no big deal, you'll just have to manually clone and update your repo, then start PDJ *(you could use a crontab with regular intervals)*
# Usage
## Download
Download the pre-compiled binaries from the release page or build it yourself.
## Build it yourself
```bash
# Build on Debian
git clone < url of this repo >
cd ProxmoxDeploy
apt update & & apt install -y build-essential patchelf
pip install nuitka
pip install -r requirements.txt
python -m nuitka --onefile run.py --output-filename="ProxmoxDeploy"
```
*Also see the ``Dockerfile`` and ``.drone.yml`` for more information.*
## Run it
```bash
# Run it
./ProxmoxDeploy --repo /path/to/repo
```
2023-06-11 22:10:22 +02:00
2023-06-14 15:52:30 +02:00
# Documentation
2023-06-12 10:13:31 +02:00
## Configuration
2023-06-14 15:52:30 +02:00
### General
Before configuring your LXC and VM, you must decide how you'll run this program.
As it requires SSH for some actions, you have two options:
- Run it directly on the Proxmox VE host ** (recommended)** *(refered as `local`)*
- No configuration needed
- You can use Git(ea)/Drone actions to run it automatically as soon as a change is pushed.
- Run it on another machine and connect via SSH
- You'll need to setup passwordless SSH connection between your machine and the Proxmox VE host.
2023-06-12 10:13:31 +02:00
### Proxmox VE
The Proxmox VE configuration is located in the `config.json` file.
2023-06-12 10:44:33 +02:00
```json
2023-06-12 10:13:31 +02:00
{
"pve":{
"host": "< pve host ip / hostname > ",
"user": "< user to connect via ssh > ", // usually root
"port": 22, // ssh port
"local": false // set to true if this program is running directly on the PVE without needing ssh
}
}
```
### LXC
To create a LXC, you need to create a JSON file in the `resources/lxc/<id of lxc>` folder.
You can look at the example with ID 100 in the `resources/lxc/100` folder.
Here is an example config with all available parameters :
*Note : this is not valid JSON, it's just for documentation purposes, if you want to copy the file, use the one in the resources folder*
2023-06-12 10:44:33 +02:00
```json
2023-06-12 10:13:31 +02:00
{
"lxc_hostname": "traefik", //hostname of the lxc
// the os block contains the os type
// alpine | archlinux | centos | debian | devuan | fedora | gentoo | nixos | opensuse | ubuntu | unmanaged
"os": {
"name": "alpine",
"release": "3.17"
},
// the resources block contains the resources given to the lxc
"resources": {
"cpu": "2", // number of cpu cores
"memory": "1024", // memory (ram) in MB
"swap": "256", // swap in MB
"disk": "8", // disk size in GB
"storage": "local-lvm" // the proxmox storage to use
},
// the network block contains the network configuration
"network": {
"bridge": "vmbr0", // the proxmox bridge to use, vmbr0 is the default one
"ipv4": "dhcp", // ipv4 address, dhcp for dhcp, auto for auto, or an ip address
"ipv6": "auto", // ipv6 address, dhcp for dhcp, auto for auto, or an ip address
"mac": "92:A6:71:77:8E:D8", // mac address, leave empty for random
"gateway4": "", // ipv4 gateway, leave empty for auto/dhcp
"gateway6": "", // ipv6 gateway, leave empty for auto/dhcp
"vlan": "" // vlan id, leave empty for no vlan
},
// the options block contains various options for the lxc
"options": {
"privileged": "false", // set to true to run the lxc in privileged mode
"start_on_boot": "false", // set to true to start the lxc on boot
"startup_order": 2, // the startup order of the lxc
"password": "qwertz1234", // the password of the root user, leave empty for none
"tags": "2-proxy+auth" // tags for the lxc to display in the proxmox web ui
},
```
2023-06-12 10:44:33 +02:00
*Tip : have a look at the [man page ](https://pve.proxmox.com/pve-docs/pct.1.html ) of the `pct` command to see how the values should look.*
2023-06-12 10:13:31 +02:00
2023-06-11 22:10:22 +02:00
## Creation
In the creation section, you have the option to define conditions for checking whether your LXC/VM has been previously configured.
If all of these conditions are met, the script will proceed directly to the deploy section and execute the necessary steps to update it. *(This indicates that your LXC/VM has already been configured, and we want to avoid erasing any existing settings/config.)*
However, if **any** of the conditions fail to match, the script will process to the creation steps section and execute **all** the commands again.
## Conditions
### File
The file condition will check if a file exists or not inside the LXC/VM.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"conditions": {
2023-06-12 10:13:31 +02:00
// use a single file
2023-06-11 22:10:22 +02:00
"file": "/var/data/traefikv2/traefik.toml"
2023-06-13 15:29:51 +02:00
// or use a list
"file": ["/var/data/traefikv2/traefik.toml", "/var/data/config/traefikv2/docker-compose.yml"]
2023-06-11 22:10:22 +02:00
}
```
It can be an array of file using ``["file1", "file2"]`` or just one file in double quote ``"file"``.
### Folder
The folder condition will check if a folder exists or not inside the LXC/VM.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"conditions": {
2023-06-12 10:13:31 +02:00
// use a single folder
2023-06-11 22:10:22 +02:00
"folder": "/var/data/traefikv2"
2023-06-13 15:29:51 +02:00
// or use a list
"folder": ["/var/data/traefikv2", "/var/data/config/traefikv2"]
2023-06-11 22:10:22 +02:00
}
```
It can be an array of folders using ``["folder1", "folder2"]`` or just one folder in double quote ``"file"``.
### Programs
The programs condition will check if a program is installed or not in the LXC/VM.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"conditions": {
2023-06-12 10:13:31 +02:00
// use a single program
2023-06-11 22:10:22 +02:00
"program": "docker"
2023-06-13 15:29:51 +02:00
// or use a list
"program": ["docker", "docker-compose"]
2023-06-11 22:10:22 +02:00
}
```
2023-06-12 10:13:31 +02:00
It can be an array of programs using ``["program1", "program2"]`` or just one program in double quote ``"program"``.
2023-06-11 22:10:22 +02:00
*Note:This uses `which` to check if the program matches to anything*
2023-06-12 10:13:31 +02:00
### Command
The command condition will check if a command returns a specific value.
```json
"conditions": {
"command": "whoami",
"value": "root"
}
```
*Note: This uses `bash -c` to execute the command*
*Note: If value is an integer, it will look for the return code, if it's a string it's check the output.*
### Docker
The docker condition will check if a docker (or podman) container is running or not.
2023-06-12 10:44:33 +02:00
```json
2023-06-12 10:13:31 +02:00
"conditions": {
// use a single container
"container": "traefikv2"
2023-06-13 15:29:51 +02:00
// or use a list
2023-06-12 10:13:31 +02:00
"container": ["traefikv2", "portainer"]
}
```
2023-06-11 22:10:22 +02:00
## Steps
**Note: Paths**
When you have to specify a path, you can use ``/global/`` to use the global folder (`resources/< script s | file > / ` ) .
If nothing is specified, the script will use the VM/LXC folder (`resources/lxc/< id > /`).
*The comments in the JSON below are only for documentation purposes and are not valid JSON, remove them before running.*
### Script
The script step will execute a script.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "script",
2023-06-12 11:10:22 +02:00
// use path for local scripts
2023-06-16 13:36:11 +02:00
"path": "global/install-docker.sh" // path in repo (here: resources/scripts/install-docker.sh)
2023-06-12 11:10:22 +02:00
// or use url for remote scripts
"url": "https://xyz.abc/scripts/install-docker.sh" // remote url
// or use lxc_path for scripts inside the lxc
"lxc_path": "/root/install-docker.sh" // lxc path
2023-06-11 22:10:22 +02:00
}
]
```
### File
2023-06-12 15:15:51 +02:00
The file step will create / copy a file to the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
2023-06-12 15:15:51 +02:00
"type": "file_create",
"path": "/var/data/traefikv2/traefik.toml", // lxc/vm path
"permissions": "644" // (optional) permissions of the file
}
]
```
```json
"steps": [
{
"type": "file_copy",
2023-06-12 10:13:31 +02:00
"path": "traefik.toml", // local path (here: resources/lxc/< id > /traefik.toml)
2023-06-13 15:29:51 +02:00
"destination": "/var/data/traefikv2/", // lxc/vm path
2023-06-12 15:15:51 +02:00
"permissions": "644" // (optional) permissions of the file
2023-06-11 22:10:22 +02:00
}
]
```
2023-06-12 15:15:51 +02:00
*Note: `file_copy` creates the folder if it doesn't exist*
2023-06-11 22:10:22 +02:00
### Folder
The folder step will copy a folder to the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
2023-06-12 15:15:51 +02:00
"type": "folder_create",
"path": "/var/data/traefikv2", // lxc/vm path
"permissions": "755" // (optional) permissions of the folder
}
]
```
```json
"steps": [
{
"type": "folder_copy",
2023-06-13 15:29:51 +02:00
"path": "data/", // local path (here: resources/lxc/< id > /data/)
"destination": "/var/", // lxc/vm path
2023-06-12 15:15:51 +02:00
"permissions": "755" // (optional) permissions of the folder
2023-06-11 22:10:22 +02:00
}
]
```
2023-06-12 15:15:51 +02:00
*Note: `folder_copy` creates the folder if it doesn't exist*
2023-06-11 22:10:22 +02:00
### Command
The command step will execute a command on the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "command",
2023-06-12 10:13:31 +02:00
"command": "whoami", // command to execute
2023-06-12 15:15:51 +02:00
"working_directory": "/var/data/config/traefikv2" // (optional) lxc/vm path
2023-06-11 22:10:22 +02:00
}
]
```
### Docker
2023-06-12 15:15:51 +02:00
The docker step will execute a command inside a docker container running on the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "docker",
2023-06-12 15:15:51 +02:00
"container": "< container-name > ", // docker container name
"command": "< command-to-run-inside > " // docker command to execute
2023-06-11 22:10:22 +02:00
}
]
```
### Docker-compose
The docker-compose step will execute a docker-compose command on the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "docker-compose",
2023-06-12 10:13:31 +02:00
"command": "up -d", // docker-compose command to execute
"working_directory": "/var/data/config/traefikv2" // lxc/vm path
2023-06-11 22:10:22 +02:00
}
]
```
*Note : Here, why not use the `command` step? Docker Compose can sometimes be executed with `docker-compose` or `docker compose` , the script will take care of choosing the correct one.*
### Git
The git step will clone a git repo on the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "git",
2023-06-12 10:13:31 +02:00
"url": "https://git.abc.xyz/abc/abc.git", // git url to clone
"destination": "/root/" // lxc/vm path
2023-06-11 22:10:22 +02:00
}
]
```
2023-06-13 15:29:51 +02:00
*Note: At the moment, no authentication is supported, so only works on public repo.*
2023-06-11 22:10:22 +02:00
### Download
The download step will download a file on the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "download",
2023-06-12 10:13:31 +02:00
// download a single file
"url": "https://git.abc.xyz/file.tar.gz", // download url
2023-06-13 15:29:51 +02:00
// or use a list of urls
"url": ["https://git.abc.xyz/file1.tar.gz", "https://git.abc.xyz/file2.tar.gz"] // download urls
2023-06-12 10:13:31 +02:00
"destination": "/tmp/" // lxc/vm path
2023-06-11 22:10:22 +02:00
}
]
```
### Extract archive (tar/zip)
The unzip step will unzip a file in the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "unzip",
2023-06-12 10:13:31 +02:00
"path": "/tmp/file.tar.gz", // lxc/vm path to the archive
"destination": "/var/data/config/traefikv2" // (optional) lxc/vm path to extract the archive, will use archive parent directory if blank
2023-06-11 22:10:22 +02:00
}
]
```
*Note : At the the moment, only tar and zip are supported.*
### Install package
The install-package step will install a package on the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "install-package",
2023-06-12 10:13:31 +02:00
// install a single package
"package": "git",
2023-06-13 15:29:51 +02:00
// or use a list of packages
"package": ["git", "docker"]
2023-06-11 22:10:22 +02:00
}
]
```
*Note : At the the moment, only apt, apk, dnf, yum are supported.*
*Warning : Packages can have different names depending on the Linux distribution.*
### Remove package
The remove-package step will remove a package on the VM/LXC.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "remove-package",
2023-06-12 10:13:31 +02:00
// remove a single package
"package": "git"
2023-06-13 15:29:51 +02:00
// or use a list of packages
"package": ["git", "docker"]
2023-06-11 22:10:22 +02:00
}
]
```
*Note : At the the moment, only apt, apk, dnf, yum are supported.*
*Warning : Packages can have different names depending on the Linux distribution.*
2023-06-12 16:18:09 +02:00
### Power
2023-06-11 22:10:22 +02:00
The reboot step will reboot the VM/LXC.
```json
"steps": [
{
"type": "reboot"
}
]
```
2023-06-12 16:18:09 +02:00
The start step will start the VM/LXC.
```json
"steps": [
{
"type": "start"
}
]
```
The stop step will stop the VM/LXC.
```json
"steps": [
{
"type": "stop"
}
]
```
2023-06-11 22:10:22 +02:00
### Replace in file
The replace-in-file step will replace a string in a file.
2023-06-12 10:44:33 +02:00
```json
2023-06-11 22:10:22 +02:00
"steps": [
{
"type": "replace-in-file",
2023-06-12 10:13:31 +02:00
// replace in a single file
"path": "/var/data/config/traefikv2/traefik.toml", // inside lxc/vm
2023-06-13 15:29:51 +02:00
// or use a list of files
"path": ["/var/data/config/traefikv2/traefik.toml", "/var/data/config/traefikv2/traefik2.toml"] // inside lxc/vm
2023-06-12 10:13:31 +02:00
"search": "abc", // string to search
"replace": "xyz", // string to replace
"case_sensitive": true, // (optional) case sensitive? default: true
2023-06-11 22:10:22 +02:00
}
]
2023-06-12 10:13:31 +02:00
```