From 513b096e6effd0904fc15aa25304c78acb34b4d8 Mon Sep 17 00:00:00 2001 From: "CanbiZ (MickLesk)" <47820557+MickLesk@users.noreply.github.com> Date: Mon, 29 Dec 2025 17:22:57 +0100 Subject: [PATCH] Add OCI container deployment script for Proxmox VE This script provides a deployment helper for OCI containers on Proxmox VE 9.1, including functions for checking Proxmox version, parsing image references, and deploying containers with customizable options. --- tools/pve/oci-deploy.sh | 344 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 tools/pve/oci-deploy.sh diff --git a/tools/pve/oci-deploy.sh b/tools/pve/oci-deploy.sh new file mode 100644 index 000000000..12dfb4ba2 --- /dev/null +++ b/tools/pve/oci-deploy.sh @@ -0,0 +1,344 @@ +#!/usr/bin/env bash +# Maintainer: MickLesk (CanbiZ) +# Copyright (c) 2021-2025 community-scripts ORG +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# OCI Container Deployment Helper for Proxmox VE 9.1+ + +set -euo pipefail +shopt -s inherit_errexit nullglob + +# Color codes +YW=$(echo "\033[33m") +BL=$(echo "\033[36m") +RD=$(echo "\033[01;31m") +BGN=$(echo "\033[4;92m") +GN=$(echo "\033[1;92m") +DGN=$(echo "\033[32m") +CL=$(echo "\033[m") +BFR="\\r\\033[K" +HOLD="-" +CM="${GN}✓${CL}" +CROSS="${RD}✗${CL}" + +msg_info() { + local msg="$1" + echo -ne " ${HOLD} ${YW}${msg}..." +} + +msg_ok() { + local msg="$1" + echo -e "${BFR} ${CM} ${GN}${msg}${CL}" +} + +msg_error() { + local msg="$1" + echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}" +} + +# Check if running on Proxmox VE 9.1+ +check_proxmox_version() { + if ! command -v pveversion &>/dev/null; then + msg_error "This script must be run on Proxmox VE" + exit 1 + fi + + local pve_version=$(pveversion | grep -oP 'pve-manager/\K[0-9.]+' | cut -d. -f1,2) + local major=$(echo "$pve_version" | cut -d. -f1) + local minor=$(echo "$pve_version" | cut -d. -f2) + + if [[ "$major" -lt 9 ]] || { [[ "$major" -eq 9 ]] && [[ "$minor" -lt 1 ]]; }; then + msg_error "Proxmox VE 9.1 or higher required (current: $pve_version)" + exit 1 + fi +} + +# Parse OCI image reference +parse_image_ref() { + local image_ref="$1" + local registry="" + local image="" + local tag="latest" + + # Handle different formats: + # - nginx:latest + # - docker.io/library/nginx:latest + # - ghcr.io/user/repo:tag + + if [[ "$image_ref" =~ ^([^/]+\.[^/]+)/ ]]; then + # Has registry prefix (contains dot) + registry="${BASH_REMATCH[1]}" + image_ref="${image_ref#*/}" + else + # Use docker.io as default + registry="docker.io" + fi + + # Extract tag if present + if [[ "$image_ref" =~ :([^:]+)$ ]]; then + tag="${BASH_REMATCH[1]}" + image="${image_ref%:*}" + else + image="$image_ref" + fi + + # Add library/ prefix for official docker hub images + if [[ "$registry" == "docker.io" ]] && [[ ! "$image" =~ / ]]; then + image="library/$image" + fi + + echo "$registry/$image:$tag" +} + +# Show usage +usage() { + cat </dev/null; then + msg_error "Failed to create container" + exit 1 + fi + + msg_ok "Container created (ID: $vmid)" + + # Set environment variables if provided + if [[ ${#env_vars[@]} -gt 0 ]]; then + msg_info "Configuring environment variables" + for env_var in "${env_vars[@]}"; do + local key="${env_var%%=*}" + local value="${env_var#*=}" + pct set "$vmid" --env "$key=$value" >/dev/null 2>&1 + done + msg_ok "Environment variables configured (${#env_vars[@]} variables)" + fi + + # Start container if requested + if [[ "$start_after" == "1" ]]; then + msg_info "Starting container" + if pct start "$vmid" >/dev/null 2>&1; then + msg_ok "Container started successfully" + + # Wait for network + sleep 3 + local container_ip=$(pct exec "$vmid" -- hostname -I 2>/dev/null | awk '{print $1}' || echo "N/A") + + echo -e "\n${GN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}" + echo -e "${BL}Container Information:${CL}" + echo -e " ID: ${GN}$vmid${CL}" + echo -e " Name: ${GN}$name${CL}" + echo -e " Image: ${GN}$full_image${CL}" + echo -e " IP: ${GN}$container_ip${CL}" + echo -e " Status: ${GN}Running${CL}" + echo -e "${GN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}\n" + else + msg_error "Failed to start container" + fi + else + echo -e "\n${GN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}" + echo -e "${BL}Container Information:${CL}" + echo -e " ID: ${GN}$vmid${CL}" + echo -e " Name: ${GN}$name${CL}" + echo -e " Image: ${GN}$full_image${CL}" + echo -e " Status: ${YW}Stopped${CL}" + echo -e "\n${YW}Start with: pct start $vmid${CL}" + echo -e "${GN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CL}\n" + fi +} + +# Parse command line arguments +IMAGE="" +NAME="" +VMID="" +CORES="2" +MEMORY="2048" +DISK="8" +STORAGE="" +NETWORK="vmbr0" +IP="dhcp" +GATEWAY="" +PRIVILEGED="0" +START="0" +ENV_VARS=() +VOLUMES=() + +while [[ $# -gt 0 ]]; do + case $1 in + -h | --help) + usage + ;; + -n | --name) + NAME="$2" + shift 2 + ;; + -i | --vmid) + VMID="$2" + shift 2 + ;; + -c | --cores) + CORES="$2" + shift 2 + ;; + -m | --memory) + MEMORY="$2" + shift 2 + ;; + -d | --disk) + DISK="$2" + shift 2 + ;; + -s | --storage) + STORAGE="$2" + shift 2 + ;; + --network) + NETWORK="$2" + shift 2 + ;; + --ip) + IP="$2" + shift 2 + ;; + --gateway) + GATEWAY="$2" + shift 2 + ;; + -e | --env) + ENV_VARS+=("$2") + shift 2 + ;; + -v | --volume) + VOLUMES+=("$2") + shift 2 + ;; + --privileged) + PRIVILEGED="1" + shift + ;; + --start) + START="1" + shift + ;; + -*) + echo "Unknown option: $1" + usage + ;; + *) + IMAGE="$1" + shift + ;; + esac +done + +# Check if image is provided +if [[ -z "$IMAGE" ]]; then + msg_error "No image specified" + usage +fi + +# Deploy the container +deploy_oci_container "$IMAGE" "$NAME" "$VMID" "$CORES" "$MEMORY" "$DISK" "$STORAGE" "$NETWORK" "$IP" "$GATEWAY" "$PRIVILEGED" "$START" "${ENV_VARS[@]}" + +exit 0