Last active
June 29, 2023 18:00
-
-
Save chpego/5237835272ad18a315e862c4e9974972 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Setup script environment | |
set -o errexit #Exit immediately if a pipeline returns a non-zero status | |
set -o errtrace #Trap ERR from shell functions, command substitutions, and commands from subshell | |
set -o nounset #Treat unset variables as an error | |
set -o pipefail #Pipe will exit with last non-zero status if applicable | |
shopt -s expand_aliases | |
alias die='EXIT=$? LINE=$LINENO error_exit' | |
trap die ERR | |
trap cleanup EXIT | |
function error_exit() { | |
trap - ERR | |
local DEFAULT='Unknown failure occured.' | |
local REASON="\e[97m${1:-$DEFAULT}\e[39m" | |
local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE" | |
msg "$FLAG $REASON" | |
[ ! -z ${CTID-} ] && cleanup_ctid | |
exit $EXIT | |
} | |
function warn() { | |
local REASON="\e[97m$1\e[39m" | |
local FLAG="\e[93m[WARNING]\e[39m" | |
msg "$FLAG $REASON" | |
} | |
function info() { | |
local REASON="$1" | |
local FLAG="\e[36m[INFO]\e[39m" | |
msg "$FLAG $REASON" | |
} | |
function msg() { | |
local TEXT="$1" | |
echo -e "$TEXT" | |
} | |
function cleanup_ctid() { | |
if [ ! -z ${MOUNT+x} ]; then | |
pct unmount ${CTID} | |
fi | |
if $(pct status ${CTID} &>/dev/null); then | |
if [ "$(pct status ${CTID} | awk '{print $2}')" == "running" ]; then | |
pct stop ${CTID} | |
fi | |
pct destroy ${CTID} | |
elif [ "$(pvesm list $STORAGE --vmid ${CTID})" != "" ]; then | |
pvesm free $ROOTFS | |
fi | |
} | |
function cleanup() { | |
popd >/dev/null | |
rm -rf $TEMP_DIR | |
} | |
function load_module() { | |
if ! $(lsmod | grep -Fq $1); then | |
modprobe $1 &>/dev/null || \ | |
die "Failed to load '$1' module." | |
fi | |
MODULES_PATH=/etc/modules | |
if ! $(grep -Fxq "$1" $MODULES_PATH); then | |
echo "$1" >> $MODULES_PATH || \ | |
die "Failed to add '$1' module to load at boot." | |
fi | |
} | |
TEMP_DIR=$(mktemp -d) | |
pushd $TEMP_DIR >/dev/null | |
# Download setup script | |
wget -qL https://gist.github.com/chpego/5237835272ad18a315e862c4e9974972/raw/396dc3dfda991c3caf7c64306993c417a7b32936/setup.sh | |
# Detect modules and automatically load at boot | |
load_module aufs | |
load_module overlay | |
# Select storage location | |
while read -r line; do | |
TAG=$(echo $line | awk '{print $1}') | |
TYPE=$(echo $line | awk '{printf "%-10s", $2}') | |
FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}') | |
ITEM=" Type: $TYPE Free: $FREE " | |
OFFSET=2 | |
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then | |
MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET)) | |
fi | |
STORAGE_MENU+=( "$TAG" "$ITEM" "OFF" ) | |
done < <(pvesm status -content rootdir | awk 'NR>1') | |
if [ $((${#STORAGE_MENU[@]}/3)) -eq 0 ]; then | |
warn "'Container' needs to be selected for at least one storage location." | |
die "Unable to detect valid storage location." | |
elif [ $((${#STORAGE_MENU[@]}/3)) -eq 1 ]; then | |
STORAGE=${STORAGE_MENU[0]} | |
else | |
while [ -z "${STORAGE:+x}" ]; do | |
STORAGE=$(whiptail --title "Storage Pools" --radiolist \ | |
"Which storage pool you would like to use for the container?\n\n" \ | |
16 $(($MSG_MAX_LENGTH + 23)) 6 \ | |
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3) || exit | |
done | |
fi | |
info "Using '$STORAGE' for storage location." | |
# Get the next guest VM/LXC ID | |
CTID=$(pvesh get /cluster/nextid) | |
info "Container ID is ${CTID}." | |
# Download latest Debian 10 Turnkey core LXC template | |
msg "Updating LXC template list..." | |
pveam update >/dev/null | |
msg "Downloading LXC template..." | |
OSTYPE=debian | |
OSVERSION=${OSTYPE}-11-turnkey-core | |
mapfile -t TEMPLATES < <(pveam available -section turnkeylinux | sed -n "s/.*\(${OSVERSION}.*\)/\1/p" | sort -t - -k 2 -V) | |
TEMPLATE="${TEMPLATES[-1]}" | |
pveam download local $TEMPLATE >/dev/null || | |
die "A problem occured while downloading the LXC template." | |
# Create variables for container disk | |
STORAGE_TYPE=$(pvesm status -storage $STORAGE | awk 'NR>1 {print $2}') | |
case $STORAGE_TYPE in | |
dir|nfs) | |
DISK_EXT=".raw" | |
DISK_REF="${CTID}/" | |
;; | |
zfspool) | |
DISK_PREFIX="subvol" | |
DISK_FORMAT="subvol" | |
;; | |
esac | |
DISK=${DISK_PREFIX:-vm}-${CTID}-disk-0${DISK_EXT-} | |
ROOTFS=${STORAGE}:${DISK_REF-}${DISK} | |
# Create LXC | |
msg "Creating LXC container..." | |
DISK_SIZE=10G | |
pvesm alloc $STORAGE ${CTID} $DISK $DISK_SIZE --format ${DISK_FORMAT:-raw} >/dev/null | |
if [ "$STORAGE_TYPE" == "zfspool" ]; then | |
warn "Some containers may not work properly due to ZFS not supporting 'fallocate'." | |
else | |
mkfs.ext4 $(pvesm path $ROOTFS) &>/dev/null | |
fi | |
ARCH=$(dpkg --print-architecture) | |
#-----replace HOSTNAME here---- | |
HOSTNAME=Frigate | |
TEMPLATE_STRING="local:vztmpl/${TEMPLATE}" | |
pct create ${CTID} $TEMPLATE_STRING -arch $ARCH -features nesting=1,keyctl=1 \ | |
-hostname $HOSTNAME -net0 name=eth0,bridge=vmbr0,ip=dhcp -onboot 1 \ | |
-ostype $OSTYPE -rootfs $ROOTFS,size=$DISK_SIZE -storage $STORAGE >/dev/null | |
# Modify LXC permissions to support Docker | |
LXC_CONFIG=/etc/pve/lxc/${CTID}.conf | |
cat <<EOF >> $LXC_CONFIG | |
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file 0, 0 | |
lxc.mount.entry: /dev/bus/usb/002 dev/bus/usb/002 none bind,optional,create=dir 0, 0 | |
lxc.cgroup.devices.allow: c 226:128 rwm | |
lxc.cgroup.devices.allow: c 189:144 rwm | |
lxc.cgroup.devices.allow: c 189:* rwm | |
lxc.cap.drop: | |
EOF | |
# Set container timezone to match host | |
MOUNT=$(pct mount ${CTID} | cut -d"'" -f 2) | |
ln -fs $(readlink /etc/localtime) ${MOUNT}/etc/localtime | |
pct unmount ${CTID} && unset MOUNT | |
# Setup container | |
msg "Starting LXC container..." | |
pct start ${CTID} | |
pct push ${CTID} setup.sh /setup.sh -perms 755 | |
pct exec ${CTID} /setup.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Setup script environment | |
set -o errexit #Exit immediately if a pipeline returns a non-zero status | |
set -o errtrace #Trap ERR from shell functions, command substitutions, and commands from subshell | |
set -o nounset #Treat unset variables as an error | |
set -o pipefail #Pipe will exit with last non-zero status if applicable | |
shopt -s expand_aliases | |
alias die='EXIT=$? LINE=$LINENO error_exit' | |
trap die ERR | |
trap 'die "Script interrupted."' INT | |
function error_exit() { | |
trap - ERR | |
local DEFAULT='Unknown failure occured.' | |
local REASON="\e[97m${1:-$DEFAULT}\e[39m" | |
local FLAG="\e[91m[ERROR:LXC] \e[93m$EXIT@$LINE" | |
msg "$FLAG $REASON" | |
exit $EXIT | |
} | |
function msg() { | |
local TEXT="$1" | |
echo -e "$TEXT" | |
} | |
# Prepare container OS | |
msg "Setting up container OS..." | |
sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen | |
locale-gen >/dev/null | |
apt-get -y purge openssh-{client,server} >/dev/null | |
apt-get autoremove >/dev/null | |
# Update container OS | |
msg "Updating container OS..." | |
apt-get update --allow-releaseinfo-change >/dev/null | |
apt-get -qqy upgrade &>/dev/null | |
# Install prerequisites | |
# msg "Installing prerequisites..." | |
ARCH=$(dpkg --print-architecture) | |
# Customize Docker configuration | |
msg "Customizing Docker..." | |
DOCKER_CONFIG_PATH='/etc/docker/daemon.json' | |
mkdir -p $(dirname $DOCKER_CONFIG_PATH) | |
cat >$DOCKER_CONFIG_PATH <<'EOF' | |
{ | |
"log-driver": "journald" | |
} | |
EOF | |
# Install Docker | |
msg "Installing Docker..." | |
apt -qqy install docker.io &>/dev/null | |
systemctl enable docker &>/dev/null | |
systemctl start docker &>/dev/null | |
# Installing Frigate | |
msg "Installing Frigate..." | |
docker volume create frigate_media >/dev/null | |
docker volume create frigate_config >/dev/null | |
FRIGATE_PATH_CONFIG=$(docker volume inspect --format '{{ .Mountpoint }}' frigate_config) | |
docker run -d \ | |
--name frigate \ | |
--restart=unless-stopped \ | |
--mount type=tmpfs,target=/tmp/cache,tmpfs-size=1000000000 \ | |
--device /dev/dri/renderD128 \ | |
--device /dev/bus/usb:/dev/bus/usb \ | |
--shm-size=64mb \ | |
-v frigate_media:/media/frigate \ | |
-v ${FRIGATE_PATH_CONFIG}/config.yml:/config/config.yml:ro \ | |
-v /etc/localtime:/etc/localtime:ro \ | |
-e FRIGATE_RTSP_PASSWORD='password' \ | |
-p 5000:5000 \ | |
-p 1935:1935 \ | |
ghcr.io/blakeblackshear/frigate:stable &>/dev/null | |
# Customize container | |
msg "Customizing container..." | |
rm /etc/motd # Remove message of the day after login | |
rm /etc/update-motd.d/10-uname # Remove kernel information after login | |
touch ~/.hushlogin # Remove 'Last login: ' and mail notification after login | |
GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf" | |
mkdir -p $(dirname $GETTY_OVERRIDE) | |
cat << EOF > $GETTY_OVERRIDE | |
[Service] | |
ExecStart= | |
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM | |
EOF | |
systemctl daemon-reload | |
systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//') | |
# Cleanup container | |
msg "Cleanup..." | |
rm -rf /setup.sh /var/{cache,log}/* /var/lib/apt/lists/* |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment