Running DotCMS on Podman in Rootless Mode

Running DotCMS on Podman in Rootless Mode

Introduction

We are currently developing comprehensive documentation for running DotCMS with Podman in rootless mode. This guide provides initial findings and configurations to get you started and provide you with our working configuration as is. We are actively working with customers to understand their specific needs and challenges, and we welcome any questions or feedback you may have about running DotCMS in this environment.

Version Requirements

This guide has been tested with:

  • Podman version 4.6.1

  • podman-compose version 1.3.0

Understanding Volume Management and User Mapping

Named Volumes Location

When using named volumes in rootless mode, Podman stores all volume data in your user's home directory at:

~/.local/share/containers/storage/volumes

For example, if your compose file defines volumes like this:

volumes:
  cms-shared:
  dbdata:
  opensearch-data:

These volumes will be created as subdirectories:

~/.local/share/containers/storage/volumes/cms-shared/_data
~/.local/share/containers/storage/volumes/dbdata/_data
~/.local/share/containers/storage/volumes/opensearch-data/_data

User Namespace Mapping

A crucial concept in rootless Podman is that even though containers may appear to run as different users inside the container (like uid 999 for PostgreSQL), the files on the host system should be owned by your host user account. This is achieved through user namespace mapping.

For example, if your host user has UID 1000, you would configure the services like this:

services:
  db:
  user: "999:999"  # This is what the process sees inside the container
  userns_mode: "keep-id:uid=999,gid=999"  # This maps to your host user (1000)

When you check the files on the host system, they should be owned by your user account (UID 1000), even though inside the container they appear to be owned by UID 999. This mapping ensures proper file permissions while maintaining container security.

System Configuration Check

Before proceeding with providing you further detailed targeted instructions if required,  we need to understand your current system configuration. Please run the following command and share the output:

podman info

This command provides essential information about your system's configuration, including:

  • Rootless mode status

  • cgroups version

  • Network backend

  • User namespace mappings

  • Security settings

Based on your system's configuration, we can provide targeted instructions for any necessary updates.

Complete Example Configuration

Below is a full example of a podman-compose.yaml file that supports rootless mode operation we have tested on our servers:

version: "3.9"
x-podman:
  in_pod: false  # Required when using userns options

# Create these networks before running compose
networks:
  db_net:
    external: true    # Create with: podman network create db_net
  opensearch_net:
    external: true    # Create with: podman network create opensearch_net

volumes:
  cms-shared:
  dbdata:
  opensearch-data:

services:
  db:
    image: pgvector/pgvector:pg16
    command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB'
    environment:
      POSTGRES_USER: 'dotcmsdbuser'
      POSTGRES_PASSWORD: 'password'
      POSTGRES_DB: 'dotcms'
    user: "999:999"
    userns_mode: "keep-id:uid=999,gid=999"
    volumes:
      - dbdata:/var/lib/postgresql/data
    networks:
      - db_net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dotcmsdbuser -d dotcms -h localhost -p 5432"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    ports:
      - "5432:5432"

  opensearch:
    image: opensearchproject/opensearch:1
    environment:
      cluster.name: "elastic-cluster"
      discovery.type: "single-node"
      bootstrap.memory_lock: "true"
      OPENSEARCH_JAVA_OPTS: "-Xmx1G"
      network.host: "0.0.0.0"
      http.cors.enabled: "true"
      http.cors.allow-origin: "*"
      plugins.security.disabled: "true"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"]
      interval: 10s
      timeout: 5s
      retries: 5
    user: "1000:1000"
    userns_mode: "keep-id:uid=1000,gid=1000"
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    ports:
      - "9200:9200"
      - "9600:9600"
    volumes:
      - opensearch-data:/usr/share/opensearch/data
    networks:
      - opensearch_net
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 2G

  dotcms:
    image: dotcms/dotcms:latest
    environment:
      CMS_JAVA_OPTS: '-Xmx1g '
      LANG: 'C.UTF-8'
      TZ: 'UTC'
      DB_BASE_URL: "jdbc:postgresql://db/dotcms"
      DB_USERNAME: 'dotcmsdbuser'
      DB_PASSWORD: 'password'
      DOT_DATASOURCE_PROVIDER_STRATEGY_CLASS: com.dotmarketing.db.SystemEnvDataSourceStrategy
      DOT_ES_AUTH_BASIC_PASSWORD: 'admin'
      DOT_ES_ENDPOINTS: 'http://opensearch:9200'
      DOT_INITIAL_ADMIN_PASSWORD: 'admin'
      DOT_DOTCMS_CLUSTER_ID: 'dotcms-production'
      GLOWROOT_ENABLED: 'true'
      GLOWROOT_WEB_UI_ENABLED: 'true'
    depends_on:
      - db
      - opensearch
    user: "65001:65001"
    userns_mode: "keep-id:uid=65001,gid=65001"
    volumes:
      - cms-shared:/data/shared
    networks:
      - db_net
      - opensearch_net
    ports:
      - "8082:8082"
      - "8443:8443"
      - "4000:4000"  # Glowroot web UI port

 

Setup Instructions

  1. First, create the required networks:

podman network create db_net
podman network create opensearch_net

  1. For host volume mappings (instead of named volumes), add the SELinux context:

volumes:
  - /host/path/data:/container/path/data:Z  # For single container access
  # or
  - /host/path/data:/container/path/data:z  # For multi-container access

  1. Verify volume permissions and ownership:

ls -la ~/.local/share/containers/storage/volumes/*/

  1. Launch the stack:

podman-compose up -d

Known Issues and Solutions

Port Conflict Resolution

If you encounter port conflicts (particularly with port 5432) when restarting:

  1. Stop all containers:

podman-compose down
  1. Kill the rootlessport process:

pkill rootlessport
  1. Restart the stack:

podman-compose up -d

Volume Permission Issues

If you encounter permission issues with volumes:

  1. Check the ownership of volume directories:

ls -la ~/.local/share/containers/storage/volumes/*/
  1. Verify that the files are owned by your host user ID

  2. Confirm that the user namespace mapping in the compose file matches your host user ID

Additional Support

We are actively developing more detailed technical documentation on the full installation update steps.

Please feel free to reach out with any questions about:

  • System configuration requirements

  • User namespace mapping

  • Network configuration

  • Volume management

  • Resource limits

  • Security considerations

  • Performance optimization

We are committed to helping you successfully deploy DotCMS using Podman in rootless mode and welcome your feedback and questions as we continue to develop our documentation.

Next Steps

  1. Please run podman info and share the output so we can provide targeted configuration instructions for your environment.

  2. Review the provided compose file and let us know if you need any clarification or have specific requirements.

  3. Share any specific concerns or requirements about your deployment environment.

We're here to help ensure a smooth deployment of DotCMS in your Podman environment.

)