From 03eedf5a9dcc6c810c91cfdf8db0d29c2817d113 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Tue, 30 Dec 2025 12:50:43 +0100 Subject: [PATCH] Refactor Dockerfile for Portainer Agent setup --- portainer_agent/Dockerfile | 218 +++++++++++++++++++++---------------- 1 file changed, 123 insertions(+), 95 deletions(-) diff --git a/portainer_agent/Dockerfile b/portainer_agent/Dockerfile index 82606c047..1d142ced0 100644 --- a/portainer_agent/Dockerfile +++ b/portainer_agent/Dockerfile @@ -1,117 +1,145 @@ -# Portainer Agent with bashio main + simplified protection mode check -# Fix for: FATAL: PROTECTION MODE IS ENABLED! error when protection mode is OFF -# Approach: Level 1 (standard bashio) + Level 2 (socket fallback) +#============================# +# ALEXBELGIUM'S DOCKERFILE # +#============================# +# _.------. +# _.-` ('>.-`"""-. +# '.--'` _'` _ .--.) +# -' '-.-';` ` +# ' - _.' ``'--. +# '---` .-'""` +# /` +#=== Home Assistant Addon ===# +################# +# 1 Build Image # +################# + +# Must be declared before first FROM ARG BUILD_FROM -ARG BUILD_ARCH + +# Get agent +FROM portainer/agent:alpine as original_agent +ENV PORTAINER_AGENT_ARGS="" + +# Build using base FROM $BUILD_FROM -# Step 1: Replace bashio v0.17.5 with main branch for improved API error handling -RUN rm -rf /usr/lib/bashio /usr/bin/bashio && \ - curl -f -J -L -o /tmp/bashio.tar.gz \ - "https://github.com/hassio-addons/bashio/archive/main.tar.gz" && \ - test -f /tmp/bashio.tar.gz && test -s /tmp/bashio.tar.gz || \ - (echo "ERROR: bashio download failed or file is empty" && exit 1) && \ - mkdir /tmp/bashio && \ - tar -xzf /tmp/bashio.tar.gz --strip 1 -C /tmp/bashio || \ - (echo "ERROR: bashio tar extraction failed" && exit 1) && \ - test -d /tmp/bashio/lib || \ - (echo "ERROR: bashio lib directory not found after extraction" && exit 1) && \ - mv /tmp/bashio/lib /usr/lib/bashio && \ - ln -s /usr/lib/bashio/bashio /usr/bin/bashio && \ - rm -rf /tmp/bashio /tmp/bashio.tar.gz +# Copy Portainer agent binaries +COPY --from=original_agent /app /app -# Step 2: Get agent from official image -COPY --from=FROM portainer/agent:alpine /app /app - -# Step 3: Add tzdata and timezone support +# Add tzdata RUN apk add --no-cache tzdata ADD https://github.com/golang/go/raw/master/lib/time/zoneinfo.zip /zoneinfo.zip ENV ZONEINFO /zoneinfo.zip -# Step 4: Set S6 init system wait times +################## +# 2 Modify Image # +################## + +# Set S6 wait time ENV S6_CMD_WAIT_FOR_SERVICES=1 \ S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \ S6_SERVICES_GRACETIME=0 -# Step 5: Copy rootfs from official image -COPY --from=FROM portainer/agent:alpine / / +################## +# 3 Install apps # +################## -# Step 6: Override the run script with simplified protection mode check -RUN mkdir -p /etc/services.d/portainer_agent +# Add rootfs +COPY rootfs/ / -RUN cat > /etc/services.d/portainer_agent/run <<'EOF' -#!/usr/bin/with-contenv bashio -# shellcheck shell=bash -set -e -# Home Assistant Community Add-on: portainer_agent -# PATCHED: Simplified protection mode check with socket fallback +# Uses /bin for compatibility purposes +# hadolint ignore=DL4005 +RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \ + if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi -bashio::require.unprotected.fixed() { - local protected +# Modules +ARG MODULES="00-banner.sh 01-custom_script.sh 00-global_var.sh" - bashio::log.info "Checking protection mode..." +# Automatic modules download +ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automodules.sh" "/ha_automodules.sh" +RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh - # Level 1: Try standard bashio method - protected=$(bashio::addon.protected 'self' 2>/dev/null || echo "unknown") +# Manual apps +ENV PACKAGES="nginx" - if [[ "${protected}" != "unknown" ]]; then - # API call succeeded - use result - bashio::log.debug "Protection mode: ${protected}" - if [[ "${protected}" == "false" ]] || [[ -z "${protected}" ]]; then - return 0 - fi - else - # Level 2: Fallback - Check Docker socket directly - # Logic: If protection mode is OFF, Docker socket WILL be accessible - bashio::log.warning "Could not determine protection mode via API, checking Docker socket..." +# Automatic apps & bashio +ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_autoapps.sh" "/ha_autoapps.sh" +RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.sh - if [ -S /run/docker.sock ]; then - bashio::log.info "Docker socket is accessible - protection mode is OFF" - return 0 - else - bashio::log.fatal "Docker socket not accessible!" - return 1 - fi +################ +# 4 Entrypoint # +################ + +# Add entrypoint +ENV S6_STAGE2_HOOK=/ha_entrypoint.sh +ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_entrypoint.sh" "/ha_entrypoint.sh" + +# Entrypoint modifications +ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_entrypoint_modif.sh" "/ha_entrypoint_modif.sh" +RUN chmod 777 /ha_entrypoint.sh /ha_entrypoint_modif.sh && /ha_entrypoint_modif.sh && rm /ha_entrypoint_modif.sh + +RUN chmod a+x /usr/sbin/healthcheck && \ + chmod a+x /usr/sbin/wait-for-signal +WORKDIR "/app" +ENTRYPOINT [ "/init" ] + +############ +# 5 Labels # +############ + +ARG BUILD_ARCH +ARG BUILD_DATE +ARG BUILD_DESCRIPTION +ARG BUILD_NAME +ARG BUILD_REF +ARG BUILD_REPOSITORY +ARG BUILD_VERSION +ENV BUILD_VERSION="${BUILD_VERSION}" +LABEL \ + io.hass.name="${BUILD_NAME}" \ + io.hass.description="${BUILD_DESCRIPTION}" \ + io.hass.arch="${BUILD_ARCH}" \ + io.hass.type="addon" \ + io.hass.version=${BUILD_VERSION} \ + maintainer="alexbelgium (https://github.com/alexbelgium)" \ + org.opencontainers.image.title="${BUILD_NAME}" \ + org.opencontainers.image.description="${BUILD_DESCRIPTION}" \ + org.opencontainers.image.vendor="Home Assistant Add-ons" \ + org.opencontainers.image.authors="alexbelgium (https://github.com/alexbelgium)" \ + org.opencontainers.image.licenses="MIT" \ + org.opencontainers.image.url="https://github.com/alexbelgium" \ + org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \ + org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \ + org.opencontainers.image.created=${BUILD_DATE} \ + org.opencontainers.image.revision=${BUILD_REF} \ + org.opencontainers.image.version=${BUILD_VERSION} + +################# +# 6 Healthcheck # +################# + +# Avoid spamming logs +# hadolint ignore=SC2016 +RUN \ + # Handle Apache configuration + if [ -d /etc/apache2/sites-available ]; then \ + for file in /etc/apache2/sites-*/*.conf; do \ + sed -i '/ /etc/nginx/nginx.conf.new && \ + mv /etc/nginx/nginx.conf.new /etc/nginx/nginx.conf; \ fi - # If we get here, protection mode is ON - bashio::log.fatal "PROTECTION MODE IS ENABLED!" - bashio::log.fatal "" - bashio::log.fatal "To be able to use this add-on, you'll need to disable" - bashio::log.fatal "protection mode on this add-on. Without it, the add-on" - bashio::log.fatal "is unable to access Docker." - bashio::log.fatal "" - bashio::log.fatal "Steps:" - bashio::log.fatal " - Go to the Supervisor Panel." - bashio::log.fatal " - Click on this add-on." - bashio::log.fatal " - Set the 'Protection mode' switch to off." - bashio::log.fatal " - Restart the add-on." - bashio::log.fatal "" - bashio::log.fatal "Access to Docker allows you to do really powerful things" - bashio::log.fatal "including complete destruction of your system." - bashio::log.fatal "Please, be sure you know what you are doing before" - bashio::log.fatal "enabling this feature (and this add-on)!" - return 1 -} - -# Call our fixed function -bashio::require.unprotected.fixed - -bashio::log.info "Starting Portainer Agent" - -# Launch app -cd /app || true -if bashio::config.has_value 'PORTAINER_AGENT_ARGS'; then - ./agent "$PORTAINER_AGENT_ARGS" -else - ./agent -fi -EOF - -RUN chmod +x /etc/services.d/portainer_agent/run - -ENTRYPOINT ["/init"] - -HEALTHCHECK --interval=5s --start-period=30s --timeout=5s --retries=3 \ - CMD /usr/sbin/healthcheck || exit 1 +ENV HEALTH_PORT="" \ + HEALTH_URL="" +HEALTHCHECK \ + --interval=5s \ + --retries=5 \ + --start-period=30s \ + --timeout=25s \ + CMD healthcheck &>/dev/null || exit 1