#!/bin/bash # shellcheck disable=SC2086,SC2046,SC2155 # # nginx-controller - https://phus.lu/code/register-nginx-conf.bash # # @reboot root nohup /bin/bash /home/phuslu/web/code/register-nginx-conf.bash /dev/null & # # Copyright (c) 2024 Phus Lu # # Authors: Phus Lu # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # NGINX_SITES_DIRECTORY=${NGINX_SITES_DIRECTORY:-/etc/nginx/sites-enabled} pidtree() ( # https://superuser.com/a/784102/114255 [ -n "$ZSH_VERSION" ] && setopt shwordsplit declare -A childs while read pid ppid; do childs[$ppid]+=" $pid" done < <(ps -e -o pid= -o ppid=) walk() { for i in ${childs[$1]}; do walk $i done echo $1 } for i in "$@";do walk $i done ) generate_nginx_conf () { local cid=$1 local name=$2 local ipaddr=$3 local port=$4 local domain=$5 echo "# generated by $0 # registered for ${cid} upstream ${name}.internal { server ${ipaddr}:${port}; }" if [ "${domain}" != "" ]; then echo " server { listen 80; listen [::]:80; server_name ${domain}; location / { proxy_pass http://${name}.internal; proxy_http_version 1.1; proxy_set_header Host \$http_host; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection Upgrade; proxy_read_timeout 180; proxy_connect_timeout 180; proxy_send_timeout 180; send_timeout 180; } }" fi } update_nginx_conf () { local ns=$1 local cid=$2 local pid=$3 if [[ $(ctr -n ${ns} container info ${cid}) =~ (\.|\/|host)name\":\ \"/?([^\"]+)\", ]]; then local name=${BASH_REMATCH[2]} else return fi if [[ $(nsenter -t ${pid} -n ip -o -4 a) =~ [0-9]+:\ e[a-z0-9]+\ +inet\ ([0-9\.]+) ]]; then local ipaddr=${BASH_REMATCH[1]} fi local IFS=$'\0' readarray -d '' environ ${NGINX_SITES_DIRECTORY}/${name}.internal if nginx -t; then nginx -s reload fi } remove_nginx_conf () { local ns=$1 local cid=$2 rm -f $(grep -l "^# registered for ${cid}" ${NGINX_SITES_DIRECTORY}/*.internal) if nginx -t; then nginx -s reload fi } list_watch () { ctr namespace ls -q | while read -r ns; do ctr -n ${ns} task ls | while read -r cid pid status; do if [ "$status" != "RUNNING" ]; then continue fi update_nginx_conf ${ns} ${cid} ${pid} done done ctr events | while read -r line; do if [[ $line =~ \ ([a-z0-9\.\-_]+)\ /tasks/start\ \{\"container_id\":\"([0-9a-f]+)\",\"pid\":([0-9]+) ]]; then update_nginx_conf "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" elif [[ $line =~ \ ([a-z0-9\.\-_]+)\ /tasks/delete\ \{\"container_id\":\"([0-9a-f]+)\" ]]; then remove_nginx_conf "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" fi done } trap 'kill $(pidtree $$)' EXIT list_watch