#!/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