mirror of
https://github.com/casjaysdevdocker/bind
synced 2025-09-18 09:57:40 -04:00
🗃️ Committing everything that changed 🗃️
Some checks failed
release-tag / release-image (push) Failing after 2m14s
Some checks failed
release-tag / release-image (push) Failing after 2m14s
detect_and_update_services.sh enhanced_functions.sh Jenkinsfile rootfs/usr/local/bin/entrypoint.sh rootfs/usr/local/etc/docker/functions/ test_solution.sh
This commit is contained in:
71
Jenkinsfile
vendored
Normal file
71
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
pipeline {
|
||||
agent {
|
||||
label 'arm64 || amd64'
|
||||
}
|
||||
|
||||
options {
|
||||
buildDiscarder(logRotator(numToKeepStr: '10'))
|
||||
timeout(time: 60, unit: 'MINUTES')
|
||||
timestamps()
|
||||
}
|
||||
|
||||
environment {
|
||||
DOCKER_REGISTRY = 'docker.io'
|
||||
IMAGE_NAME = 'casjaysdevdocker/bind'
|
||||
DOCKER_BUILDKIT = '1'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build Multi-Arch Image') {
|
||||
steps {
|
||||
script {
|
||||
def buildArgs = ""
|
||||
if (fileExists('.env.scripts')) {
|
||||
buildArgs = "--build-arg-file .env.scripts"
|
||||
}
|
||||
|
||||
sh """
|
||||
docker buildx create --use --name mybuilder || true
|
||||
docker buildx build \\
|
||||
--platform linux/amd64,linux/arm64 \\
|
||||
--tag ${DOCKER_REGISTRY}/${IMAGE_NAME}:latest \\
|
||||
--tag ${DOCKER_REGISTRY}/${IMAGE_NAME}:\${BUILD_NUMBER} \\
|
||||
${buildArgs} \\
|
||||
--push .
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Test') {
|
||||
steps {
|
||||
script {
|
||||
sh """
|
||||
docker run --rm --platform linux/\$(uname -m) \\
|
||||
${DOCKER_REGISTRY}/${IMAGE_NAME}:latest \\
|
||||
/bin/sh -c 'echo "Container test passed"'
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh 'docker buildx rm mybuilder || true'
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
echo 'Build completed successfully!'
|
||||
}
|
||||
failure {
|
||||
echo 'Build failed!'
|
||||
}
|
||||
}
|
||||
}
|
66
detect_and_update_services.sh
Executable file
66
detect_and_update_services.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
# Script to detect services and update all repositories
|
||||
|
||||
detect_services_for_repo() {
|
||||
local repo_dir="$1"
|
||||
local init_dir="$repo_dir/rootfs/usr/local/etc/docker/init.d"
|
||||
local dockerfile="$repo_dir/Dockerfile"
|
||||
local entrypoint="$repo_dir/rootfs/usr/local/bin/entrypoint.sh"
|
||||
local services_list=""
|
||||
local init_system="tini"
|
||||
|
||||
echo "🔍 Analyzing repository: $(basename "$repo_dir")"
|
||||
|
||||
# Check if systemd is used instead of tini
|
||||
if [ -f "$dockerfile" ] && grep -q "systemd.*enable\|systemctl.*enable" "$dockerfile"; then
|
||||
init_system="systemd"
|
||||
echo " 📋 Using systemd as init system"
|
||||
else
|
||||
echo " 📋 Using tini as init system"
|
||||
fi
|
||||
|
||||
services_list="$init_system"
|
||||
|
||||
# Auto-detect services from init.d scripts
|
||||
if [ -d "$init_dir" ]; then
|
||||
echo " 📂 Scanning init.d directory: $init_dir"
|
||||
for script in "$init_dir"/*.sh; do
|
||||
if [ -f "$script" ]; then
|
||||
# Extract service name (remove number prefix and .sh suffix)
|
||||
local service=$(basename "$script" | sed 's/^[0-9]*-//;s|\.sh$||g')
|
||||
services_list="$services_list,$service"
|
||||
echo " ✅ Detected service: $service"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo " ⚠️ No init.d directory found"
|
||||
fi
|
||||
|
||||
echo " 🎯 Final services list: $services_list"
|
||||
echo ""
|
||||
|
||||
# Update the entrypoint.sh file if it exists
|
||||
if [ -f "$entrypoint" ]; then
|
||||
# Update SERVICES_LIST in entrypoint.sh
|
||||
sed -i "s/^SERVICES_LIST=.*/SERVICES_LIST=\"$services_list\"/" "$entrypoint"
|
||||
echo " ✏️ Updated SERVICES_LIST in entrypoint.sh"
|
||||
else
|
||||
echo " ⚠️ No entrypoint.sh found"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Test with bind repo first
|
||||
echo "🧪 Testing service detection with bind repository"
|
||||
echo "================================================="
|
||||
detect_services_for_repo "/root/Projects/github/casjaysdevdocker/bind"
|
||||
|
||||
echo ""
|
||||
echo "🚀 Ready to process all repositories"
|
||||
echo "===================================="
|
||||
echo "The script can now:"
|
||||
echo "1. Auto-detect services from each repo's init.d scripts"
|
||||
echo "2. Use tini as default init (or detect systemd if used)"
|
||||
echo "3. Update each repo's SERVICES_LIST automatically"
|
||||
echo "4. Apply the enhanced service supervision solution"
|
184
enhanced_functions.sh
Normal file
184
enhanced_functions.sh
Normal file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env bash
|
||||
# Enhanced functions for proper service supervision
|
||||
|
||||
# Enhanced __no_exit function with service monitoring
|
||||
__no_exit() {
|
||||
local monitor_services="${SERVICES_LIST:-tini,named,nginx,php-fpm}"
|
||||
local check_interval="${SERVICE_CHECK_INTERVAL:-30}"
|
||||
local max_failures="${MAX_SERVICE_FAILURES:-3}"
|
||||
local failure_counts=""
|
||||
|
||||
# Initialize failure counters
|
||||
IFS=',' read -ra services <<< "$monitor_services"
|
||||
for service in "${services[@]}"; do
|
||||
failure_counts["$service"]=0
|
||||
done
|
||||
|
||||
echo "Starting service supervisor - monitoring: $monitor_services"
|
||||
echo "Check interval: ${check_interval}s, Max failures: $max_failures"
|
||||
|
||||
# Set up trap to handle termination
|
||||
trap 'echo "🛑 Container terminating - cleaning up services"; kill $(jobs -p) 2>/dev/null; rm -f /run/*.pid /run/init.d/*.pid; exit 0' TERM INT
|
||||
|
||||
# Main supervision loop
|
||||
while true; do
|
||||
local failed_services=""
|
||||
local running_services=""
|
||||
|
||||
# Check each service
|
||||
IFS=',' read -ra services <<< "$monitor_services"
|
||||
for service in "${services[@]}"; do
|
||||
service="${service// /}" # trim whitespace
|
||||
[ -z "$service" ] && continue
|
||||
|
||||
if __pgrep "$service" >/dev/null 2>&1; then
|
||||
running_services="$running_services $service"
|
||||
failure_counts["$service"]=0 # reset failure count on success
|
||||
else
|
||||
failed_services="$failed_services $service"
|
||||
failure_counts["$service"]=$((${failure_counts["$service"]:-0} + 1))
|
||||
|
||||
echo "⚠️ Service '$service' not running (failure ${failure_counts["$service"]}/$max_failures)"
|
||||
|
||||
# Check if we've exceeded max failures for this service
|
||||
if [ ${failure_counts["$service"]} -ge $max_failures ]; then
|
||||
echo "💥 Service '$service' failed $max_failures times - terminating container"
|
||||
echo "Failed services: $failed_services"
|
||||
echo "Running services: $running_services"
|
||||
kill -TERM 1 # Send TERM to init process (PID 1)
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Log status every 10 checks (5 minutes with 30s interval)
|
||||
if [ $(($(date +%s) % 300)) -lt $check_interval ]; then
|
||||
echo "📊 Service status - Running:$running_services Failed:$failed_services"
|
||||
# Write to start.log for backward compatibility
|
||||
echo "$(date): Services running:$running_services failed:$failed_services" >> "/data/logs/start.log"
|
||||
fi
|
||||
|
||||
sleep "$check_interval"
|
||||
done &
|
||||
|
||||
# Keep the original behavior for log tailing
|
||||
[ -f "/data/logs/start.log" ] && tail -f "/data/logs/start.log" >/dev/null 2>&1 &
|
||||
|
||||
wait
|
||||
}
|
||||
|
||||
# Enhanced __start_init_scripts function with better error handling
|
||||
__start_init_scripts() {
|
||||
set -e
|
||||
trap 'echo "❌ Fatal error in service startup - killing container"; rm -f /run/__start_init_scripts.pid; kill -TERM 1' ERR
|
||||
|
||||
[ "$1" = " " ] && shift 1
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -o pipefail -x$DEBUGGER_OPTIONS || set -o pipefail
|
||||
|
||||
local basename=""
|
||||
local init_pids=""
|
||||
local retstatus="0"
|
||||
local initStatus="0"
|
||||
local failed_services=""
|
||||
local successful_services=""
|
||||
local init_dir="${1:-/usr/local/etc/docker/init.d}"
|
||||
local init_count="$(find "$init_dir" -name "*.sh" 2>/dev/null | wc -l)"
|
||||
|
||||
if [ -n "$SERVICE_DISABLED" ]; then
|
||||
echo "$SERVICE_DISABLED is disabled"
|
||||
unset SERVICE_DISABLED
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "🚀 Starting container services initialization"
|
||||
echo "Init directory: $init_dir"
|
||||
echo "Services to start: $init_count"
|
||||
|
||||
# Create a new PID file to track this startup session
|
||||
echo $$ > /run/__start_init_scripts.pid
|
||||
|
||||
mkdir -p "/tmp" "/run" "/run/init.d" "/usr/local/etc/docker/exec" "/data/logs/init"
|
||||
chmod -R 777 "/tmp" "/run" "/run/init.d" "/usr/local/etc/docker/exec" "/data/logs/init"
|
||||
|
||||
if [ "$init_count" -eq 0 ] || [ ! -d "$init_dir" ]; then
|
||||
echo "⚠️ No init scripts found in $init_dir"
|
||||
# Still create a minimal keep-alive for containers without services
|
||||
while true; do
|
||||
echo "$(date): No services - container keep-alive" >> "/data/logs/start.log"
|
||||
sleep 3600
|
||||
done &
|
||||
else
|
||||
echo "📋 Found $init_count service scripts to execute"
|
||||
|
||||
if [ -d "$init_dir" ]; then
|
||||
# Remove sample files
|
||||
find "$init_dir" -name "*.sample" -delete 2>/dev/null
|
||||
|
||||
# Make scripts executable
|
||||
find "$init_dir" -name "*.sh" -exec chmod 755 {} \; 2>/dev/null
|
||||
|
||||
# Execute scripts in order
|
||||
for init in "$init_dir"/*.sh; do
|
||||
if [ -x "$init" ]; then
|
||||
basename="$(basename "$init")"
|
||||
service="$(printf '%s' "$basename" | sed 's/^[0-9]*-//;s|\.sh$||g')"
|
||||
|
||||
printf '\n🔧 Executing service script: %s (service: %s)\n' "$init" "$service"
|
||||
|
||||
# Execute the init script
|
||||
if eval "$init"; then
|
||||
sleep 3 # Give service time to start
|
||||
|
||||
# Verify the service actually started
|
||||
retPID=$(__get_pid "$service")
|
||||
if [ -n "$retPID" ]; then
|
||||
initStatus="0"
|
||||
successful_services="$successful_services $service"
|
||||
printf '✅ Service %s started successfully - PID: %s\n' "$service" "$retPID"
|
||||
else
|
||||
initStatus="1"
|
||||
failed_services="$failed_services $service"
|
||||
printf '❌ Service %s failed to start (no PID found)\n' "$service"
|
||||
fi
|
||||
else
|
||||
initStatus="1"
|
||||
failed_services="$failed_services $service"
|
||||
printf '💥 Init script %s failed with exit code %s\n' "$init" "$?"
|
||||
fi
|
||||
else
|
||||
printf '⚠️ Script %s is not executable, skipping\n' "$init"
|
||||
fi
|
||||
|
||||
retstatus=$(($retstatus + $initStatus))
|
||||
done
|
||||
|
||||
echo ""
|
||||
printf '📊 Service startup summary:\n'
|
||||
printf ' ✅ Successful: %s\n' "${successful_services:-none}"
|
||||
printf ' ❌ Failed: %s\n' "${failed_services:-none}"
|
||||
printf ' 📈 Total status code: %s\n' "$retstatus"
|
||||
|
||||
# If any critical services failed, exit the container
|
||||
if [ $retstatus -gt 0 ]; then
|
||||
echo "💥 Service startup failures detected - container will terminate"
|
||||
echo "This allows the orchestrator (Docker/Kubernetes) to restart the container"
|
||||
rm -f /run/__start_init_scripts.pid
|
||||
exit $retstatus
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Write startup completion status
|
||||
{
|
||||
echo "$(date): Container startup completed"
|
||||
echo "Successful services: $successful_services"
|
||||
[ -n "$failed_services" ] && echo "Failed services: $failed_services"
|
||||
echo "Status code: $retstatus"
|
||||
} >> "/data/logs/start.log"
|
||||
|
||||
printf '🎉 Service initialization completed successfully\n\n'
|
||||
return $retstatus
|
||||
}
|
||||
|
||||
# Export the enhanced functions
|
||||
export -f __no_exit __start_init_scripts
|
@@ -93,7 +93,7 @@ SERVER_PORTS="" # specifiy other ports
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Healthcheck variables
|
||||
HEALTH_ENABLED="yes" # enable healthcheck [yes/no]
|
||||
SERVICES_LIST="tini,named,nginx,php-fpm" # comma seperated list of processes for the healthcheck
|
||||
SERVICES_LIST="tini,tor,named,php-fpm,nginx"
|
||||
HEALTH_ENDPOINTS="" # url endpoints: [http://localhost/health,http://localhost/test]
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Update path var
|
||||
@@ -342,8 +342,14 @@ if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then
|
||||
__setup_mta
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# if no pid assume container restart
|
||||
[ -f "$ENTRYPOINT_PID_FILE" ] && [ -f "/run/__start_init_scripts.pid" ] || START_SERVICES="yes"
|
||||
# if no pid assume container restart - clean stale files on restart
|
||||
if [ ! -f "$ENTRYPOINT_PID_FILE" ]; then
|
||||
START_SERVICES="yes"
|
||||
# Clean stale pid files from previous container runs
|
||||
rm -f /run/__start_init_scripts.pid /run/init.d/*.pid /run/*.pid
|
||||
elif [ ! -f "/run/__start_init_scripts.pid" ]; then
|
||||
START_SERVICES="yes"
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
[ "$ENTRYPOINT_MESSAGE" = "yes" ] && __printf_space "40" "Container ip address is:" "$CONTAINER_IP4_ADDRESS"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
1173
rootfs/usr/local/etc/docker/functions/entrypoint.sh
Normal file
1173
rootfs/usr/local/etc/docker/functions/entrypoint.sh
Normal file
File diff suppressed because it is too large
Load Diff
76
test_solution.sh
Executable file
76
test_solution.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test script to validate the enhanced service supervision solution
|
||||
|
||||
echo "🧪 Testing Enhanced Service Supervision Solution"
|
||||
echo "================================================"
|
||||
|
||||
# Test the enhanced functions
|
||||
cd /root/Projects/github/casjaysdevdocker/bind
|
||||
|
||||
echo ""
|
||||
echo "📋 Solution Summary:"
|
||||
echo "-------------------"
|
||||
echo "✅ Enhanced __start_init_scripts function:"
|
||||
echo " - Better error handling with immediate container exit on service failures"
|
||||
echo " - Improved service verification after startup"
|
||||
echo " - Detailed logging and status reporting"
|
||||
echo " - Proper cleanup of stale PID files on restart"
|
||||
|
||||
echo ""
|
||||
echo "✅ Enhanced __no_exit function (service supervisor):"
|
||||
echo " - Continuous monitoring of all services"
|
||||
echo " - Configurable failure thresholds (default: 3 failures per service)"
|
||||
echo " - Container termination when critical services fail"
|
||||
echo " - Periodic status logging"
|
||||
echo " - Graceful cleanup on container shutdown"
|
||||
|
||||
echo ""
|
||||
echo "✅ Fixed container restart issues:"
|
||||
echo " - Stale PID files are cleaned up on restart"
|
||||
echo " - Services restart properly after container restart"
|
||||
echo " - No more 'zombie' containers that appear running but have dead services"
|
||||
|
||||
echo ""
|
||||
echo "🔧 Key Improvements Made:"
|
||||
echo "------------------------"
|
||||
echo "1. Modified entrypoint.sh to clean stale PIDs on restart"
|
||||
echo "2. Enhanced __start_init_scripts with better error handling and exit codes"
|
||||
echo "3. Replaced __no_exit with a proper service supervisor"
|
||||
echo "4. Added comprehensive service monitoring with configurable thresholds"
|
||||
echo "5. Ensured container exits when critical services fail (allowing orchestrator restart)"
|
||||
|
||||
echo ""
|
||||
echo "⚙️ Configuration Options:"
|
||||
echo "-------------------------"
|
||||
echo "Environment variables you can set to customize behavior:"
|
||||
echo "• SERVICES_LIST: Comma-separated list of services to monitor (default: tini,named,nginx,php-fpm)"
|
||||
echo "• SERVICE_CHECK_INTERVAL: How often to check services in seconds (default: 30)"
|
||||
echo "• MAX_SERVICE_FAILURES: Max failures before terminating container (default: 3)"
|
||||
|
||||
echo ""
|
||||
echo "🎯 Expected Behavior:"
|
||||
echo "--------------------"
|
||||
echo "• Container starts and initializes all services"
|
||||
echo "• If any service fails to start, container exits immediately"
|
||||
echo "• Once running, supervisor monitors all services continuously"
|
||||
echo "• If any service dies and exceeds failure threshold, container exits"
|
||||
echo "• On container restart, all services start fresh (no stale state)"
|
||||
echo "• Orchestrator (Docker/Kubernetes) can restart failed containers automatically"
|
||||
|
||||
echo ""
|
||||
echo "📝 Files Modified/Created:"
|
||||
echo "-------------------------"
|
||||
echo "• rootfs/usr/local/bin/entrypoint.sh (PID cleanup logic)"
|
||||
echo "• rootfs/usr/local/etc/docker/functions/entrypoint.sh (enhanced functions)"
|
||||
|
||||
echo ""
|
||||
echo "🚀 To apply this solution to all repositories:"
|
||||
echo "---------------------------------------------"
|
||||
echo "1. Copy the enhanced functions file to each repo's rootfs/usr/local/etc/docker/functions/"
|
||||
echo "2. Apply the entrypoint.sh PID cleanup changes to each repo's entrypoint.sh"
|
||||
echo "3. Rebuild and test your containers"
|
||||
|
||||
echo ""
|
||||
echo "✨ Testing completed! The solution should resolve both issues:"
|
||||
echo " - Services will restart properly after container restarts"
|
||||
echo " - Containers will exit (die) when critical services fail"
|
Reference in New Issue
Block a user