Deploying OpenSearch with Podman and Quadlet for Containerized Search at Scale
OpenSearch is a powerful open-source search and analytics engine that many organizations use for log analysis, full-text search, and observability. While Kubernetes is commonly used for deploying OpenSearch clusters, there are simpler alternatives for smaller deployments or environments where Kubernetes is not available. This guide demonstrates how to deploy OpenSearch using Podman and Quadlet for a lightweight, secure, and systemd-integrated solution.
Architecture Overview
This deployment uses a layered architecture that provides stability, security, and integration with the host system:
graph TD User[User Application] -->|Search Requests| OS[OpenSearch Container] Admin[Administrator] -->|Management| SD[Systemd Service] SD -->|Controls| PC[Podman Container] PC -->|Runs| OS OS -->|Stores| Data[Persistent Volume]
subgraph "Host System" SD PC Data end
subgraph "Container" OS end
The architecture consists of:
- Podman Container: Root-less container runtime without daemon
- Quadlet: Configuration standard for systemd container integration
- OpenSearch: Search and analytics engine
- Persistent Storage: Volume mapping for durable data
- Systemd Integration: For service management and automatic restarts
Prerequisites
Before starting the implementation, ensure you have:
- Linux Distribution: Fedora, RHEL, CentOS Stream, or other Linux with Podman 4.0+
- Hardware Requirements:
- Minimum 2 cores and 4GB RAM (8GB+ recommended)
- 20GB available storage
- Software:
- Podman 4.0 or newer
- Systemd 248 or newer (for Quadlet support)
- User with sudo access
Implementation Steps
Our implementation follows a systematic approach for deploying OpenSearch with Podman and Quadlet.
1. Installing and Configuring Podman
First, let’s make sure Podman is properly installed and configured:
# Install Podman if not already installedsudo dnf install -y podman podman-docker
# Check Podman version (should be 4.0+)podman --version
# Enable and start the Podman socketsystemctl --user enable --now podman.socket
# Verify socket statussystemctl --user status podman.socket
2. Creating a Persistent Volume for OpenSearch Data
OpenSearch requires persistent storage to maintain data across container restarts:
# Create a directory for persistent datamkdir -p ~/.local/share/opensearch-data
# Set appropriate permissionschmod 777 ~/.local/share/opensearch-data
3. Testing OpenSearch with Podman
Before creating the Quadlet file, let’s test running OpenSearch with Podman directly:
# Run OpenSearch as a single-node clusterpodman run -d \ --name opensearch-node1 \ -e cluster.name=opensearch-cluster \ -e node.name=opensearch-node1 \ -e discovery.type=single-node \ -e "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" \ -e "plugins.security.disabled=true" \ -e bootstrap.memory_lock=false \ -e "path.data=/usr/share/opensearch/data" \ --ulimit nofile=65536:65536 \ -v ~/.local/share/opensearch-data:/usr/share/opensearch/data:Z,rw \ -p 19200:9200 \ -p 19600:9600 \ --user "$(id -u):$(id -g)" \ docker.io/opensearchproject/opensearch:latest
# Check if the container is runningpodman ps
# View logs to verify startuppodman logs -f opensearch-node1
4. Creating a Quadlet Configuration for OpenSearch
Now, let’s create a Quadlet file to define our OpenSearch container configuration for systemd:
# Create Quadlet directory if it doesn't existmkdir -p ~/.config/containers/systemd
# Create the Quadlet configuration filecat << EOF > ~/.config/containers/systemd/opensearch.container[Unit]Description=OpenSearch ContainerAfter=network-online.targetWants=network-online.target
[Container]Image=docker.io/opensearchproject/opensearch:latestNetwork=hostPublishPort=19200:9200PublishPort=19600:9600Volume=~/.local/share/opensearch-data:/usr/share/opensearch/data:ZEnvironment=cluster.name=opensearch-clusterEnvironment=node.name=opensearch-node1Environment=discovery.type=single-nodeEnvironment=OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512mEnvironment=plugins.security.disabled=trueEnvironment=path.data=/usr/share/opensearch/dataEnvironment=bootstrap.memory_lock=falseUlimit=nofile=65536:65536User=$(id -u):$(id -g)
[Service]Restart=alwaysTimeoutStartSec=900TimeoutStopSec=70
[Install]WantedBy=default.targetEOF
# Reload systemd to detect the new Quadlet filesystemctl --user daemon-reload
5. Managing OpenSearch with Systemd
With the Quadlet file in place, you can now manage OpenSearch using systemd:
# Enable the service to start at loginsystemctl --user enable container-opensearch.service
# Enable lingering to ensure services start at bootloginctl enable-linger $USER
# Start the OpenSearch servicesystemctl --user start container-opensearch.service
# Check service statussystemctl --user status container-opensearch.service
6. Testing OpenSearch Functionality
Once OpenSearch is running, let’s verify that it’s working properly:
# Test the OpenSearch REST APIcurl -X GET "http://localhost:19200/"
# Create a test indexcurl -X PUT "http://localhost:19200/test-index"
# Add a document to the indexcurl -X POST "http://localhost:19200/test-index/_doc" \ -H 'Content-Type: application/json' \ -d '{"title": "Test Document", "content": "This is a test document for OpenSearch."}'
# Search for documentscurl -X GET "http://localhost:19200/test-index/_search?q=test"
7. Securing OpenSearch
For production use, you should enable security features in OpenSearch:
# Stop the existing containersystemctl --user stop container-opensearch.service
# Update Quadlet configuration with security settingscat << EOF > ~/.config/containers/systemd/opensearch.container[Unit]Description=OpenSearch ContainerAfter=network-online.targetWants=network-online.target
[Container]Image=docker.io/opensearchproject/opensearch:latestNetwork=hostPublishPort=19200:9200PublishPort=19600:9600Volume=~/.local/share/opensearch-data:/usr/share/opensearch/data:ZEnvironment=cluster.name=opensearch-clusterEnvironment=node.name=opensearch-node1Environment=discovery.type=single-nodeEnvironment=OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512mEnvironment=plugins.security.disabled=falseEnvironment=OPENSEARCH_INITIAL_ADMIN_PASSWORD=StrongPasswordHereEnvironment=path.data=/usr/share/opensearch/dataEnvironment=bootstrap.memory_lock=falseUlimit=nofile=65536:65536User=$(id -u):$(id -g)
[Service]Restart=alwaysTimeoutStartSec=900TimeoutStopSec=70
[Install]WantedBy=default.targetEOF
# Reload and restart the servicesystemctl --user daemon-reloadsystemctl --user restart container-opensearch.service
# Test secured API with basic authcurl -u admin:StrongPasswordHere -X GET "http://localhost:19200/"
Advanced Configuration
Multi-node Cluster Configuration
For a more robust deployment, you can set up a multi-node cluster:
# Create Quadlet file for node 1cat << EOF > ~/.config/containers/systemd/opensearch-1.container[Unit]Description=OpenSearch Node 1After=network-online.targetWants=network-online.target
[Container]Image=docker.io/opensearchproject/opensearch:latestNetwork=hostPublishPort=19201:9200PublishPort=19601:9600Volume=~/.local/share/opensearch-data-1:/usr/share/opensearch/data:ZEnvironment=cluster.name=opensearch-clusterEnvironment=node.name=opensearch-node1Environment=discovery.seed_hosts=localhost:19301,localhost:19302Environment=cluster.initial_master_nodes=opensearch-node1,opensearch-node2Environment=OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512mEnvironment=path.data=/usr/share/opensearch/dataEnvironment=network.host=0.0.0.0Environment=transport.port=19301Environment=http.port=9200Ulimit=nofile=65536:65536User=$(id -u):$(id -g)
[Service]Restart=always
[Install]WantedBy=default.targetEOF
# Create Quadlet file for node 2cat << EOF > ~/.config/containers/systemd/opensearch-2.container[Unit]Description=OpenSearch Node 2After=network-online.targetWants=network-online.target
[Container]Image=docker.io/opensearchproject/opensearch:latestNetwork=hostPublishPort=19202:9200PublishPort=19602:9600Volume=~/.local/share/opensearch-data-2:/usr/share/opensearch/data:ZEnvironment=cluster.name=opensearch-clusterEnvironment=node.name=opensearch-node2Environment=discovery.seed_hosts=localhost:19301,localhost:19302Environment=cluster.initial_master_nodes=opensearch-node1,opensearch-node2Environment=OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512mEnvironment=path.data=/usr/share/opensearch/dataEnvironment=network.host=0.0.0.0Environment=transport.port=19302Environment=http.port=9200Ulimit=nofile=65536:65536User=$(id -u):$(id -g)
[Service]Restart=always
[Install]WantedBy=default.targetEOF
Adding OpenSearch Dashboards
To add OpenSearch Dashboards for visualization:
# Create Quadlet file for OpenSearch Dashboardscat << EOF > ~/.config/containers/systemd/opensearch-dashboards.container[Unit]Description=OpenSearch DashboardsAfter=container-opensearch.serviceRequires=container-opensearch.service
[Container]Image=docker.io/opensearchproject/opensearch-dashboards:latestPublishPort=15601:5601Environment=OPENSEARCH_HOSTS=["http://localhost:19200"]Environment=DISABLE_SECURITY_DASHBOARDS_PLUGIN=true
[Service]Restart=always
[Install]WantedBy=default.targetEOF
Monitoring and Management
Checking Container Logs
You can check the logs of your OpenSearch container using:
# View recent logssystemctl --user status container-opensearch.service
# Stream logsjournalctl --user -f -u container-opensearch.service
# Or use podman logspodman logs -f opensearch
Container Resource Management
You can adjust resource limits in your Quadlet file:
# Update resource limits in ~/.config/containers/systemd/opensearch.container[Container]# ...existing configuration...Environment=OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1gCPUQuota=200%MemoryLimit=2G
Troubleshooting
Common Issues and Solutions
Permission Denied Errors
If you encounter permission issues with the data directory:
# Fix permissionschmod 777 ~/.local/share/opensearch-data# Or use a more secure approach with appropriate ownershipchown -R $(id -u):$(id -g) ~/.local/share/opensearch-datachmod 700 ~/.local/share/opensearch-data
OpenSearch Fails to Start
If OpenSearch doesn’t start properly:
# Check for virtual memory limitscat /proc/sys/vm/max_map_count# If less than 262144, set it higher:sudo sysctl -w vm.max_map_count=262144# Make persistent by adding to /etc/sysctl.confecho "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
Service Does Not Start Automatically
If the service doesn’t start at boot:
# Verify lingering is enabledloginctl show-user $USER | grep Linger
# Enable if neededloginctl enable-linger $USER
# Verify systemd service is enabledsystemctl --user is-enabled container-opensearch.service
Security Best Practices
Network Security
- Use host firewall to restrict access to OpenSearch ports
- Configure TLS for transport and HTTP layers
- Place OpenSearch behind a reverse proxy for additional security
Authentication and Authorization
- Create custom users with limited permissions
- Use role-based access control
- Regularly rotate admin passwords
Auditing and Monitoring
- Enable audit logging
- Monitor for unauthorized access attempts
- Set up alerts for security events
Conclusion
Deploying OpenSearch with Podman and Quadlet provides a lightweight, secure, and systemd-integrated search solution without the complexity of Docker or Kubernetes. This approach offers several advantages:
- Daemonless Operation: No background daemon required, reducing resource usage
- Rootless Security: Run containers as regular users, enhancing security
- Systemd Integration: Native service management with dependencies and logging
- Portability: Works across various Linux distributions with minimal dependencies
- Simplified Management: Clear configuration files with Quadlet
Whether you’re setting up a small development environment or a production system with modest requirements, this deployment method offers a robust solution for running OpenSearch in containers.