Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Dockerfile with Runtime UID/GID Flexibility #50

Open
14 tasks
damienlaine opened this issue Nov 24, 2024 · 0 comments
Open
14 tasks

Enhance Dockerfile with Runtime UID/GID Flexibility #50

damienlaine opened this issue Nov 24, 2024 · 0 comments
Labels

Comments

@damienlaine
Copy link
Member

The current Dockerfile for the application does not allow dynamic customization of the runtime user and group, making it less flexible for deployment in diverse environments. Running the container as a non-root user is essential for adhering to best practices and ensuring security.

  1. The Dockerfiles should default to running as the www-data user (UID=33, GID=33), commonly used in web services.
  2. The containers should support runtime configuration of the user and group via USER_ID and GROUP_ID environment variables.
  3. Ownership and permissions for required directories should be dynamically adjusted at runtime through the entrypoint script.

The default behavior should be documented, with instructions for setting USER_ID and GROUP_ID as needed.

Suggestions

  1. Add gosu for Secure Runtime User Switching:

    • Install gosu in the Dockerfile to securely switch to the configured user at runtime.
  2. Set Default to www-data:

    • Default USER_ID and GROUP_ID to 33 (UID/GID for www-data) if no environment variables are set.
  3. Modify Permissions Dynamically:

    • Dynamically create the runtime user and group based on USER_ID and GROUP_ID in the entrypoint script.
    • Adjust directory permissions at runtime to ensure the configured user has the necessary access.
  4. Document Configuration:

    • Provide clear documentation for setting USER_ID and GROUP_ID environment variables at runtime.

Example Implementation

# Add gosu
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
    ffmpeg \
    git \
    gosu

Remix entrypoint.sh with

#!/bin/bash
set -a  # Export all variables

echo "RUNNING STT"

# Set default UID and GID (defaults to www-data: 33:33 if not specified)
USER_ID=${USER_ID:-33}
GROUP_ID=${GROUP_ID:-33}

# Function to create a user/group if needed and adjust permissions
function setup_user() {
    echo "Configuring runtime user with UID=$USER_ID and GID=$GROUP_ID"

    # Create group if it doesn't exist
    if ! getent group appgroup >/dev/null 2>&1; then
        echo "Creating group with GID=$GROUP_ID"
        groupadd -g "$GROUP_ID" appgroup
    fi

    # Create user if it doesn't exist
    if ! id appuser >/dev/null 2>&1; then
        echo "Creating user with UID=$USER_ID and GID=$GROUP_ID"
        useradd -m -u "$USER_ID" -g appgroup appuser
    fi

    # Adjust ownership of application directories
    echo "Adjusting ownership of application directories"
    chown -R appuser:appgroup /usr/src/app
}

# Check model format
echo "Checking model format ..."
if [ -z "$MODEL" ]; then
    echo "Model type not specified, defaulting to Whisper medium model"
    export MODEL="medium"
fi

# Validate SERVICE_MODE
if [ -z "$SERVICE_MODE" ]; then
    echo "ERROR: Must specify an environment variable SERVICE_MODE in [http | task | websocket] (None was specified)"
    exit 1
fi

# Define common functions
function check_gpu() {
    nvidia-smi > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "GPU detected"
        export GPU=1
        export OPT="--pool=solo"
    else
        echo "No GPU detected"
        export GPU=0
        export OPT=""
    fi
}

function wait_for_service() {
    local broker_url=$1
    local timeout=${2:-20}
    echo "Waiting for service broker: $broker_url (timeout: $timeout seconds)"
    /usr/src/app/wait-for-it.sh "$broker_url" --timeout="$timeout" --strict || {
        echo "ERROR: Service broker $broker_url did not respond in time"
        exit 1
    }
    echo "$broker_url is up"
}

# Setup the runtime user
setup_user

# Launch services based on SERVICE_MODE
case "$SERVICE_MODE" in
    "http")
        echo "RUNNING STT HTTP SERVER"
        exec gosu appuser python3 http_server/ingress.py --debug
        ;;
    "task")
        if [ -z "$SERVICES_BROKER" ]; then
            echo "ERROR: SERVICES_BROKER variable not specified, cannot start celery worker."
            exit 1
        fi

        check_gpu
        broker_host=$(echo "$SERVICES_BROKER" | cut -d'/' -f 3)
        wait_for_service "$broker_host"

        echo "RUNNING STT CELERY WORKER"
        exec gosu appuser celery --app=celery_app.celeryapp worker $OPT -Ofair --queues="${SERVICE_NAME}" -c "${CONCURRENCY}" -n "${SERVICE_NAME}_worker@%h"
        ;;
    "websocket")
        echo "Running Websocket server on port ${STREAMING_PORT:=80}"
        exec gosu appuser python3 websocket/websocketserver.py
        ;;
    *)
        echo "ERROR: Invalid SERVICE_MODE specified (got SERVICE_MODE=$SERVICE_MODE)"
        exit 1
        ;;
esac

echo "Service stopped"

Tasks

  • Update the Dockerfile:

    • Install gosu.
    • Use an updated entrypoint script to handle runtime UID/GID configuration.
  • Refactor Entrypoint Script:

    • Dynamically create the user and group at runtime.
    • Adjust ownership of required directories.
    • Use gosu to securely switch to the configured user.
  • Testing:

    • Test the container with the default USER_ID=33 and GROUP_ID=33 for www-data.
    • Test with custom values to ensure runtime flexibility.
    • Validate behavior with bind-mounted volumes.
  • Update Documentation:

    • Document the default USER_ID and GROUP_ID values (33 for www-data).
    • Provide examples for setting USER_ID and GROUP_ID as environment variables during runtime:
      docker run -e USER_ID=1000 -e GROUP_ID=1000 my-container
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: No status
Development

No branches or pull requests

1 participant