diff --git a/compose.database.yml b/compose.mongodb.yml similarity index 82% rename from compose.database.yml rename to compose.mongodb.yml index f2073a1..279eb11 100644 --- a/compose.database.yml +++ b/compose.mongodb.yml @@ -1,35 +1,4 @@ services: - nats: - image: docker.io/nats:${NATS_VERSION:-2.11-alpine} - restart: always - expose: - - 4222 - - 8222 - - 6222 - # healthcheck: - # test: ["CMD", "nc", "-zv", "-w", "10", "nats", "4222"] - # interval: 30s - # timeout: 10s - # retries: 10 - # start_period: 30s - command: --http_port 8222 - ports: - - "${NATS_BIND_IP:-127.0.0.1}:${NATS_PORT_NUMBER:-4222}:4222" - logging: - driver: "json-file" - labels: - container_tag: "${COMPOSE_PROJECT_NAME:-rocketchat}#nats" - - nats-exporter: - image: docker.io/natsio/prometheus-nats-exporter:${NATS_EXPORTER_VERSION:-0.17.3} - depends_on: - - nats - expose: - - 7777 - command: - - -healthz - - -varz - - "http://nats:8222" mongodb-fix-permission-container: image: docker.io/mongodb/mongodb-community-server:${MONGODB_VERSION:-8.2}-ubi8 restart: on-failure @@ -124,8 +93,6 @@ services: timeout: 10s retries: 10 start_period: 30s - ports: - - "${MONGODB_BIND_IP:-127.0.0.1}:${MONGODB_PORT_NUMBER:-27017}:${MONGODB_PORT_NUMBER:-27017}" mongodb-exporter: image: docker.io/percona/mongodb_exporter:${MONGODB_EXPORTER_VERSION:-0.44.0} @@ -139,4 +106,4 @@ services: - --compatible-mode volumes: - mongodb_data: {driver: local} + mongodb_data: { driver: local } diff --git a/compose.monitoring.yml b/compose.monitoring.yml index e58c069..95024b8 100644 --- a/compose.monitoring.yml +++ b/compose.monitoring.yml @@ -15,8 +15,6 @@ services: - --storage.tsdb.retention.time=${PROMETHEUS_RETENTION_TIME:-15d} expose: - 9090 - ports: - - ${PROMETHEUS_LISTEN_ADDR:-127.0.0.1}:${PROMETHEUS_PORT:-9090}:9090 volumes: - prometheus_tsdb:/prometheus:rw - ./files/prometheus:/etc/prometheus:Z @@ -81,8 +79,6 @@ services: restart: always expose: - 3000 - ports: - - "${GRAFANA_BIND_IP:-0.0.0.0}:${GRAFANA_HOST_PORT:-5050}:3000" volumes: - grafana_data:/var/lib/grafana:Z - ./files/grafana/dashboards:/dashboards:Z diff --git a/compose.nats.yml b/compose.nats.yml new file mode 100644 index 0000000..01dfc6e --- /dev/null +++ b/compose.nats.yml @@ -0,0 +1,41 @@ +services: + nats: + image: docker.io/nats:${NATS_VERSION:-2.11-alpine} + restart: always + expose: + - 4222 + - 8222 + - 6222 + # healthcheck: + # test: ["CMD", "nc", "-zv", "-w", "10", "nats", "4222"] + # interval: 30s + # timeout: 10s + # retries: 10 + # start_period: 30s + command: --http_port 8222 -js -sd /data + # In docker this won't have many replicas, so restart is complety data loss + volumes: + - nats_data:/data + logging: + driver: "journald" + options: + tag: "${COMPOSE_PROJECT_NAME:-rocketchat}#nats#{{.Name}}" + + nats-exporter: + image: docker.io/natsio/prometheus-nats-exporter:${NATS_EXPORTER_VERSION:-0.17.3} + depends_on: + - nats + expose: + - 7777 + command: + - -healthz + - -varz + - "http://nats:8222" + logging: + driver: "journald" + options: + tag: "${COMPOSE_PROJECT_NAME:-rocketchat}#nats-exporter#{{.Name}}" + +volumes: + nats_data: + driver: local diff --git a/docker.yml b/docker.yml index f964d3a..f1b15fe 100644 --- a/docker.yml +++ b/docker.yml @@ -11,10 +11,3 @@ services: - /var/run/docker.sock:/var/run/docker.sock:ro - /var/lib/docker/containers:/hostfs/storage:ro - rocketchat: - healthcheck: - test: ["CMD", "nc", "-zv", "-w", "10", "rocketchat", "${PORT:-3000}"] - interval: 30s - timeout: 10s - retries: 10 - start_period: 30s diff --git a/overrides/docker/compose.monitoring.yml b/overrides/docker/compose.monitoring.yml new file mode 100644 index 0000000..5c04245 --- /dev/null +++ b/overrides/docker/compose.monitoring.yml @@ -0,0 +1,5 @@ +services: + opentelemetry-logs-collector: + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - /var/lib/docker/containers:/hostfs/storage:ro diff --git a/overrides/docker/compose.yml b/overrides/docker/compose.yml new file mode 100644 index 0000000..54b61fc --- /dev/null +++ b/overrides/docker/compose.yml @@ -0,0 +1,8 @@ +services: + rocketchat: + healthcheck: + test: ["CMD", "nc", "-zv", "-w", "10", "rocketchat", "${PORT:-3000}"] + interval: 30s + timeout: 10s + retries: 10 + start_period: 30s diff --git a/overrides/podman-rootful/compose.monitoring.yml b/overrides/podman-rootful/compose.monitoring.yml new file mode 100644 index 0000000..07e6547 --- /dev/null +++ b/overrides/podman-rootful/compose.monitoring.yml @@ -0,0 +1,7 @@ +services: + opentelemetry-logs-collector: + security_opt: + - label=disable + volumes: + - /var/run/podman/podman.sock:/var/run/docker.sock:Z + - /var/lib/containers/storage/overlay-containers:/hostfs/storage:Z diff --git a/overrides/podman-rootless/compose.monitoring.yml b/overrides/podman-rootless/compose.monitoring.yml new file mode 100644 index 0000000..6412a24 --- /dev/null +++ b/overrides/podman-rootless/compose.monitoring.yml @@ -0,0 +1,7 @@ +services: + opentelemetry-logs-collector: + security_opt: + - label=disable + volumes: + - ${XDG_RUNTIME_DIR}/podman/podman.sock:/var/run/docker.sock:Z + - ${HOME}/.local/share/containers/storage/overlay-containers:/hostfs/storage:Z diff --git a/podman-rootful.yml b/podman-rootful.yml deleted file mode 100644 index 15bc5c9..0000000 --- a/podman-rootful.yml +++ /dev/null @@ -1,23 +0,0 @@ -####################################################################### -# podman-rootful.yml -# -# Compose file for running Rocket.Chat stack with Podman in rootful mode. -# -# Use this file ONLY if your Podman setup requires rootful operation. -# Rootless Podman is recommended for most users (see README). -# -# This file configures additional security options and mounts required -# for rootful Podman compatibility, especially for log collection. -# -# Usage example: -# podman-compose -f compose.monitoring.yml -f compose.traefik.yml -f compose.database.yml -f compose.yml -f podman-rootful.yml up -d -# -# For rootless mode, use podman.yml instead. -####################################################################### -services: - opentelemetry-logs-collector: - security_opt: - - label=disable - volumes: - - /var/run/podman/podman.sock:/var/run/docker.sock:Z - - /var/lib/containers/storage/overlay-containers:/hostfs/storage:Z diff --git a/run b/run new file mode 100644 index 0000000..f5ad9e2 --- /dev/null +++ b/run @@ -0,0 +1,174 @@ +#!/usr/bin/env bash + +set -euo pipefail +export VERBOSE +VERBOSE="" +# Color Definitions +RESTORE=$(tput sgr0) +RED=$(tput setaf 1) +YELLOW=$(tput setaf 3) +GREEN=$(tput setaf 2) +CYAN=$(tput setaf 6) +# Logging Functions +log:info() { + echo -e "${GREEN}[INFO]${RESTORE} $(date +'%H:%M:%S') - $1" +} + +log:debug() { + # Only prints if DEBUG environment variable is set + if [[ "${VERBOSE}" == "true" ]]; then + # debug will output to stderr, so we can log while capturing the stdout + # without breaking + echo -e "${CYAN}[DEBUG]${RESTORE} $(date +'%H:%M:%S') - ${*}" >&2 + fi +} + +log:warn() { + echo -e "${YELLOW}[WARN]${RESTORE} $(date +'%H:%M:%S') - ${*}" +} + +log:error() { + echo -e "${RED}[ERROR]${RESTORE} $(date +'%H:%M:%S') - ${*}" >&2 +} + +log:raise() { + log:error "$@" + exit 1 +} + +# store the root dir as a variable +here="$(dirname "$(readlink -f "${0}")")" + +# We use our own variable to avoid conflicting with COMPOSE_FILE, or COMPOSE_PROFILES +# Older versions might not recognize it, so we try our best to avoid confusion +ROCKETCHAT_COMPOSE_FILES="" + +add_compose_file() { + export ROCKETCHAT_COMPOSE_FILES + log:debug "Adding to compose files: ${1}" + ROCKETCHAT_COMPOSE_FILES="${ROCKETCHAT_COMPOSE_FILES} -f ${1}" +} + +add_compose_file "${here}/compose.yml" +add_compose_file "${here}/compose.mongodb.yml" +add_compose_file "${here}/compose.nats.yml" +add_compose_file "${here}/compose.monitoring.yml " +add_compose_file "${here}/compose.traefik.yml" + +OVERRIDES_DIR="" +RUNNER_CMD="" + +get_runner_config() { + export OVERRIDES_DIR + export RUNNER_CMD + if type docker2 >/dev/null 2>&1; then + RUNNER_CMD="docker compose" + OVERRIDES_DIR="overrides/docker" + elif type podman2 >/dev/null 2>&1; then + if type podman-compose >/dev/null 2>&1; then + RUNNER_CMD="podman-compose" + else + RUNNER_CMD="podman compose" + fi + + OVERRIDES_DIR="overrides/podman-rootful" + if podman info --format '{{.Host.Security.Rootless}}' 2>/dev/null | grep -q "true"; then + OVERRIDES_DIR="overrides/podman-rootless" + systemctl --user is-active podman.socket || { + log:error "Rocket.Chat requires the Podman API socket (podman.socket) to be enabled for rootless operation." + log:error "To enable it, run the following command as your regular user:" + log:error " systemctl --user enable --now podman.socket" + log:error "If you have never started the user systemd instance, you may need to run:" + log:error " loginctl enable-linger $USER" + log:error "For more information, see: https://docs.podman.io/en/latest/markdown/podman-system-service.1.html" + log:raise "podman.socket is required for this Rocket.Chat setup." + } + + systemctl --user is-enabled podman.socket || { + log:error "podman.socket is active but not enabled, this will prevent it from starting when machine reboots." + log:error "Enable the service on boot with:" + log:error " systemctl --user enable --now podman.socket" + log:error "If you see issues, ensure your user session is active (try: loginctl enable-linger $USER)." + log:raise "podman.socket must be running for this Rocket.Chat setup." + } + fi + + else + log:error "No container runner found in \$PATH" + log:raise " please check your docker or podman installations" + fi +} + +profiles() { + export ROCKETCHAT_COMPOSE_FILES + export OVERRIDES_DIR + # reset ROCKETCHAT_COMPOSE_FILES and use the provided by the user + ROCKETCHAT_COMPOSE_FILES="" + profiles_string="$(echo "$1" | tr ',' '\n')" + while read -r profile; do + [[ -z "${profile}" ]] && + continue + + base_name="compose.${profile}.yml" + + if [[ "${profile}" == "rocketchat" ]] || [[ "${profile}" == "rc" ]]; then + # keep rc name for compatibility reasons + base_name="compose.yml" + fi + + file="${here}/${base_name}" + + test -f "${file}" || + log:raise "Error loading profile ${profile}\n ${file} not found " + + add_compose_file "$file" + + override_file="${here}/${OVERRIDES_DIR}/${base_name}" + if test -f "${override_file}"; then + log:info "Found override for ${base_name} in: ${override_file}, loading it" + add_compose_file "$override_file" + fi + + done <<<"$profiles_string" +} + +compose() { + export ROCKETCHAT_COMPOSE_FILES + + log:debug "Using compose files" + log:debug "${ROCKETCHAT_COMPOSE_FILES}" + log:debug "Running command:" + log:debug "${RUNNER_CMD} ${ROCKETCHAT_COMPOSE_FILES} ${*}" + # we need the word spliting here, and it's safe because we validated previously + # shellcheck disable=SC2086 + ${RUNNER_CMD} ${ROCKETCHAT_COMPOSE_FILES} "$@" +} + +for ((i = 1; i <= $#; )); do + arg="${!i}" + case "$arg" in + -v | --verbose) + VERBOSE=true + shift + ;; + -vv | --extra-verbose) + set -x + shift + ;; + -p | --profiles | --profile) + profiles "${2}" + shift 2 + ;; + compose) + shift + # Run this before anything to setup vairables + get_runner_config + + compose "$@" + shift "$#" # clear all args + ;; + *) + log:raise "Invalid args ${*}" + ;; + esac +done