netsapiensis

rocky-opensearch

0
0
# Install this skill:
npx skills add netsapiensis/claude-code-skills --skill "rocky-opensearch"

Install specific skill from multi-skill repository

# Description

OpenSearch 3.4 cluster administration on Rocky Linux 8/9 including RPM installation, kernel tuning, single-node and multi-node cluster configuration, security plugin, index and ISM policy management, snapshots, JVM heap sizing, and performance tuning. Use when installing, configuring, or administering OpenSearch clusters.

# SKILL.md


name: rocky-opensearch
description: OpenSearch 3.4 cluster administration on Rocky Linux 8/9 including RPM installation, kernel tuning, single-node and multi-node cluster configuration, security plugin, index and ISM policy management, snapshots, JVM heap sizing, and performance tuning. Use when installing, configuring, or administering OpenSearch clusters.


OpenSearch 3.4 Cluster Administration

Installation, configuration, security, index management, snapshots, and performance tuning for OpenSearch 3.4 on Rocky Linux 8/9.

Prerequisite: See rocky-foundation for OS detection and safety tier definitions.

Installation

RPM Repository Setup

# Import GPG key  # [CONFIRM]
rpm --import https://artifacts.opensearch.org/publickeys/opensearch.pgp

# Add repository  # [CONFIRM]
cat > /etc/yum.repos.d/opensearch-3.x.repo << 'EOF'
[opensearch-3.x]
name=OpenSearch 3.x
baseurl=https://artifacts.opensearch.org/releases/bundle/opensearch/3.x/yum
enabled=1
gpgcheck=1
gpgkey=https://artifacts.opensearch.org/publickeys/opensearch.pgp
type=rpm-md
EOF

# Install OpenSearch 3.4  # [CONFIRM]
dnf install -y opensearch-3.4.0

# Install OpenSearch Dashboards (optional)  # [CONFIRM]
cat > /etc/yum.repos.d/opensearch-dashboards-3.x.repo << 'EOF'
[opensearch-dashboards-3.x]
name=OpenSearch Dashboards 3.x
baseurl=https://artifacts.opensearch.org/releases/bundle/opensearch-dashboards/3.x/yum
enabled=1
gpgcheck=1
gpgkey=https://artifacts.opensearch.org/publickeys/opensearch.pgp
type=rpm-md
EOF

dnf install -y opensearch-dashboards-3.4.0

Kernel Tuning

# Required: vm.max_map_count  # [CONFIRM]
echo "vm.max_map_count=262144" > /etc/sysctl.d/99-opensearch.conf
sysctl -p /etc/sysctl.d/99-opensearch.conf

# Verify  # [READ-ONLY]
sysctl vm.max_map_count

# File descriptor limits  # [CONFIRM]
cat > /etc/security/limits.d/opensearch.conf << 'EOF'
opensearch soft nofile 65535
opensearch hard nofile 65535
opensearch soft nproc 4096
opensearch hard nproc 4096
opensearch soft memlock unlimited
opensearch hard memlock unlimited
EOF

# Disable swap (or reduce swappiness)  # [CONFIRM]
swapoff -a                               # Temporary
# Or permanently: comment out swap in /etc/fstab
# Or set swappiness:
echo "vm.swappiness=1" >> /etc/sysctl.d/99-opensearch.conf
sysctl -p /etc/sysctl.d/99-opensearch.conf

Systemd Service Tuning

# Override systemd limits for opensearch  # [CONFIRM]
mkdir -p /etc/systemd/system/opensearch.service.d
cat > /etc/systemd/system/opensearch.service.d/override.conf << 'EOF'
[Service]
LimitNOFILE=65535
LimitNPROC=4096
LimitMEMLOCK=infinity
EOF

systemctl daemon-reload

Cluster Configuration

Configuration Files

/etc/opensearch/
├── opensearch.yml            # Main configuration
├── jvm.options               # JVM heap and GC settings
├── jvm.options.d/            # JVM options drop-in directory
├── log4j2.properties         # Logging configuration
└── opensearch-security/      # Security plugin config
    ├── config.yml
    ├── internal_users.yml
    ├── roles.yml
    ├── roles_mapping.yml
    ├── action_groups.yml
    └── tenants.yml

Single-Node Configuration

# /etc/opensearch/opensearch.yml  # [CONFIRM]
cluster.name: my-cluster
node.name: node-1

# Network
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300

# Single-node discovery
discovery.type: single-node

# Paths
path.data: /var/lib/opensearch
path.logs: /var/log/opensearch

# Security plugin (disable for development only)
# plugins.security.disabled: true

Multi-Node Configuration

# /etc/opensearch/opensearch.yml (node-1)  # [CONFIRM]
cluster.name: production-cluster
node.name: node-1

# Node roles
node.roles: [cluster_manager, data, ingest]

# Network
network.host: 10.0.0.11
http.port: 9200
transport.port: 9300

# Cluster discovery
discovery.seed_hosts:
  - 10.0.0.11
  - 10.0.0.12
  - 10.0.0.13
cluster.initial_cluster_manager_nodes:
  - node-1
  - node-2
  - node-3

# Paths
path.data: /var/lib/opensearch
path.logs: /var/log/opensearch

Node Roles

Role Purpose
cluster_manager Cluster state management (odd number, minimum 3 for HA)
data Store and search data
ingest Pre-process documents (pipelines)
coordinating Route requests (set node.roles: [])
ml Machine learning workloads

Start and Verify

# Enable and start  # [CONFIRM]
systemctl enable --now opensearch

# Check cluster health  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cluster/health?pretty
# or without security:
curl -s http://localhost:9200/_cluster/health?pretty

# Check node info  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cat/nodes?v

# Check cluster settings  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cluster/settings?include_defaults=true&flat_settings=true | python3 -m json.tool | head -50

Security Plugin

Initial Setup

# The security plugin ships with demo certificates
# For production: generate your own TLS certificates

# Security configuration directory
ls -la /etc/opensearch/opensearch-security/  # [READ-ONLY]

TLS Configuration

# /etc/opensearch/opensearch.yml -- TLS section  # [CONFIRM]
plugins.security.ssl.transport.pemcert_filepath: /etc/opensearch/certs/node.pem
plugins.security.ssl.transport.pemkey_filepath: /etc/opensearch/certs/node-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: /etc/opensearch/certs/ca.pem
plugins.security.ssl.transport.enforce_hostname_verification: true

plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: /etc/opensearch/certs/node-http.pem
plugins.security.ssl.http.pemkey_filepath: /etc/opensearch/certs/node-http-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: /etc/opensearch/certs/ca.pem

plugins.security.authcz.admin_dn:
  - "CN=admin,OU=ops,O=myorg,C=US"
plugins.security.nodes_dn:
  - "CN=node*,OU=ops,O=myorg,C=US"

Internal Users

# /etc/opensearch/opensearch-security/internal_users.yml  # [CONFIRM]
_meta:
  type: "internalusers"
  config_version: 2

admin:
  hash: "$2y$12$..."     # Generate with: /usr/share/opensearch/plugins/opensearch-security/tools/hash.sh
  reserved: true
  backend_roles:
    - "admin"
  description: "Admin user"

kibanaserver:
  hash: "$2y$12$..."
  reserved: true
  description: "Dashboards user"

readall:
  hash: "$2y$12$..."
  reserved: false
  backend_roles:
    - "readall"
  description: "Read-only user"

Apply Security Configuration

# Hash a password  # [READ-ONLY]
/usr/share/opensearch/plugins/opensearch-security/tools/hash.sh

# Apply security config changes  # [CONFIRM]
OPENSEARCH_JAVA_HOME=/usr/share/opensearch/jdk \
/usr/share/opensearch/plugins/opensearch-security/tools/securityadmin.sh \
  -cd /etc/opensearch/opensearch-security/ \
  -icl -nhnv \
  -cacert /etc/opensearch/certs/ca.pem \
  -cert /etc/opensearch/certs/admin.pem \
  -key /etc/opensearch/certs/admin-key.pem

Index Management

# List indices  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cat/indices?v&s=index

# Create index with mappings  # [CONFIRM]
curl -sk -u admin:admin -X PUT https://localhost:9200/my-index -H 'Content-Type: application/json' -d '{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "refresh_interval": "5s"
  },
  "mappings": {
    "properties": {
      "timestamp": { "type": "date" },
      "message": { "type": "text" },
      "level": { "type": "keyword" },
      "host": { "type": "keyword" }
    }
  }
}'

# Get index settings  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/my-index/_settings?pretty
curl -sk -u admin:admin https://localhost:9200/my-index/_mapping?pretty

# Delete index  # [DESTRUCTIVE]
curl -sk -u admin:admin -X DELETE https://localhost:9200/my-index

# Index stats  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/my-index/_stats?pretty
curl -sk -u admin:admin https://localhost:9200/_cat/shards?v&s=index

Index Templates

# Create index template  # [CONFIRM]
curl -sk -u admin:admin -X PUT https://localhost:9200/_index_template/logs-template -H 'Content-Type: application/json' -d '{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "message": { "type": "text" },
        "level": { "type": "keyword" }
      }
    }
  },
  "priority": 100
}'

# List templates  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_index_template?pretty

ISM (Index State Management) Policies

# Create ISM policy for log rotation  # [CONFIRM]
curl -sk -u admin:admin -X PUT https://localhost:9200/_plugins/_ism/policies/log-rotation -H 'Content-Type: application/json' -d '{
  "policy": {
    "description": "Rotate logs: warm after 7 days, cold after 30 days, delete after 90 days",
    "default_state": "hot",
    "states": [
      {
        "name": "hot",
        "actions": [
          { "rollover": { "min_index_age": "7d", "min_primary_shard_size": "30gb" } }
        ],
        "transitions": [
          { "state_name": "warm", "conditions": { "min_index_age": "7d" } }
        ]
      },
      {
        "name": "warm",
        "actions": [
          { "replica_count": { "number_of_replicas": 0 } },
          { "force_merge": { "max_num_segments": 1 } }
        ],
        "transitions": [
          { "state_name": "cold", "conditions": { "min_index_age": "30d" } }
        ]
      },
      {
        "name": "cold",
        "actions": [
          { "read_only": {} }
        ],
        "transitions": [
          { "state_name": "delete", "conditions": { "min_index_age": "90d" } }
        ]
      },
      {
        "name": "delete",
        "actions": [
          { "delete": {} }
        ]
      }
    ],
    "ism_template": [
      { "index_patterns": ["logs-*"], "priority": 100 }
    ]
  }
}'

# Check ISM policy status  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_plugins/_ism/explain/logs-*?pretty

Snapshots

Configure Snapshot Repository

# Create snapshot directory  # [CONFIRM]
mkdir -p /mnt/opensearch-snapshots
chown opensearch:opensearch /mnt/opensearch-snapshots

# Add to opensearch.yml  # [CONFIRM]
# path.repo: ["/mnt/opensearch-snapshots"]

# Restart after config change  # [CONFIRM]
systemctl restart opensearch

# Register repository  # [CONFIRM]
curl -sk -u admin:admin -X PUT https://localhost:9200/_snapshot/my-backup -H 'Content-Type: application/json' -d '{
  "type": "fs",
  "settings": {
    "location": "/mnt/opensearch-snapshots/my-backup"
  }
}'

# Verify repository  # [READ-ONLY]
curl -sk -u admin:admin -X POST https://localhost:9200/_snapshot/my-backup/_verify?pretty

Create and Restore Snapshots

# Create snapshot  # [CONFIRM]
curl -sk -u admin:admin -X PUT "https://localhost:9200/_snapshot/my-backup/snapshot-$(date +%Y%m%d)?wait_for_completion=true" -H 'Content-Type: application/json' -d '{
  "indices": "logs-*",
  "include_global_state": false
}'

# List snapshots  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_snapshot/my-backup/_all?pretty

# Snapshot status  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_snapshot/my-backup/_current?pretty

# Restore snapshot  # [DESTRUCTIVE]
curl -sk -u admin:admin -X POST https://localhost:9200/_snapshot/my-backup/snapshot-20240115/_restore -H 'Content-Type: application/json' -d '{
  "indices": "logs-2024.01.*",
  "rename_pattern": "(.+)",
  "rename_replacement": "restored-$1"
}'

# Delete old snapshot  # [DESTRUCTIVE]
curl -sk -u admin:admin -X DELETE https://localhost:9200/_snapshot/my-backup/snapshot-20240101

JVM and Performance Tuning

JVM Heap Sizing

# Set heap size (50% of available RAM, max 32GB)  # [CONFIRM]
# /etc/opensearch/jvm.options.d/heap.options
cat > /etc/opensearch/jvm.options.d/heap.options << 'EOF'
-Xms16g
-Xmx16g
EOF

# Restart required after heap change  # [CONFIRM]
systemctl restart opensearch

Rules for heap sizing:
- Set -Xms and -Xmx to the same value
- No more than 50% of available RAM (OS needs the rest for filesystem cache)
- Never exceed 32GB (compressed oops threshold)
- For dedicated nodes: min(RAM/2, 32GB)

Check JVM and Cluster Health

# Node stats  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_nodes/stats/jvm?pretty
curl -sk -u admin:admin https://localhost:9200/_nodes/stats/os?pretty

# Hot threads  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_nodes/hot_threads

# Pending tasks  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cluster/pending_tasks?pretty

# Allocation explanation  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cluster/allocation/explain?pretty

# Shard allocation  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cat/shards?v&s=state,index

Performance Settings

# /etc/opensearch/opensearch.yml -- Performance  # [CONFIRM]
# Thread pools (adjust based on workload)
thread_pool.write.queue_size: 1000
thread_pool.search.queue_size: 1000

# Circuit breakers
indices.breaker.total.limit: 70%
indices.breaker.fielddata.limit: 40%

# Indexing buffer
indices.memory.index_buffer_size: 15%

# Cache
indices.queries.cache.size: 15%

SELinux for OpenSearch

# Custom data directory  # [CONFIRM]
semanage fcontext -a -t var_lib_t "/data/opensearch(/.*)?"
restorecon -Rv /data/opensearch/

# Allow network binding  # [CONFIRM]
semanage port -a -t http_port_t -p tcp 9200
semanage port -a -t http_port_t -p tcp 9300

Firewall Rules

# Open ports  # [CONFIRM]
firewall-cmd --add-port=9200/tcp --permanent     # HTTP API
firewall-cmd --add-port=9300/tcp --permanent     # Transport (cluster)
firewall-cmd --add-port=5601/tcp --permanent     # Dashboards (if installed)
firewall-cmd --reload

# Restrict to specific sources  # [CONFIRM]
firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4"
  source address="10.0.0.0/8"
  port protocol="tcp" port="9200"
  accept'
firewall-cmd --reload

Monitoring and Troubleshooting

# Cluster health  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cluster/health?pretty

# Unassigned shards  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state

# Disk space  # [READ-ONLY]
curl -sk -u admin:admin https://localhost:9200/_cat/allocation?v

# Index sizes  # [READ-ONLY]
curl -sk -u admin:admin 'https://localhost:9200/_cat/indices?v&s=store.size:desc'

# Slow queries  # [READ-ONLY]
# Configure in opensearch.yml:
# index.search.slowlog.threshold.query.warn: 10s
# index.search.slowlog.threshold.query.info: 5s
journalctl -u opensearch | grep slowlog

When to Use This Skill

  • Installing or upgrading OpenSearch
  • Configuring cluster topology (single-node or multi-node)
  • Managing the security plugin (users, TLS, authentication)
  • Creating indices, templates, or ISM policies
  • Setting up and managing snapshots
  • Tuning JVM heap and performance settings
  • Troubleshooting cluster health issues
  • rocky-foundation -- OS detection, safety tiers, kernel tuning
  • rocky-core-system -- systemd service management
  • rocky-selinux -- SELinux contexts for OpenSearch paths/ports
  • rocky-networking -- Firewall rules for cluster ports
  • rocky-opentelemetry -- Sending logs/metrics to OpenSearch
  • rocky-borg-backup -- Backing up OpenSearch config and snapshots

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.