2018-09-21 22:00:57 +00:00
|
|
|
#!/bin/bash
|
|
|
|
|
2021-01-11 17:23:21 +00:00
|
|
|
set -eo pipefail
|
|
|
|
shopt -s nullglob
|
|
|
|
|
2020-01-26 16:14:13 +00:00
|
|
|
DO_CHOWN=1
|
2024-11-09 16:09:54 +00:00
|
|
|
if [[ "${CLICKHOUSE_RUN_AS_ROOT:=0}" = "1" || "${CLICKHOUSE_DO_NOT_CHOWN:-0}" = "1" ]]; then
|
2020-01-26 16:14:13 +00:00
|
|
|
DO_CHOWN=0
|
|
|
|
fi
|
|
|
|
|
2024-11-09 16:09:54 +00:00
|
|
|
# CLICKHOUSE_UID and CLICKHOUSE_GID are kept for backward compatibility, but deprecated
|
|
|
|
# One must use either "docker run --user" or CLICKHOUSE_RUN_AS_ROOT=1 to run the process as
|
|
|
|
# FIXME: Remove ALL CLICKHOUSE_UID CLICKHOUSE_GID before 25.3
|
|
|
|
if [[ "${CLICKHOUSE_UID:-}" || "${CLICKHOUSE_GID:-}" ]]; then
|
|
|
|
echo 'WARNING: Support for CLICKHOUSE_UID/CLICKHOUSE_GID will be removed in a couple of releases.' >&2
|
|
|
|
echo 'WARNING: Either use a proper "docker run --user=xxx:xxxx" argument instead of CLICKHOUSE_UID/CLICKHOUSE_GID' >&2
|
|
|
|
echo 'WARNING: or set "CLICKHOUSE_RUN_AS_ROOT=1" ENV to run the clickhouse-server as root:root' >&2
|
|
|
|
fi
|
2020-01-26 16:14:13 +00:00
|
|
|
|
2024-11-09 16:09:54 +00:00
|
|
|
# support `docker run --user=xxx:xxxx`
|
|
|
|
if [[ "$(id -u)" = "0" ]]; then
|
|
|
|
if [[ "$CLICKHOUSE_RUN_AS_ROOT" = 1 ]]; then
|
|
|
|
USER=0
|
|
|
|
GROUP=0
|
|
|
|
else
|
|
|
|
USER="${CLICKHOUSE_UID:-"$(id -u clickhouse)"}"
|
|
|
|
GROUP="${CLICKHOUSE_GID:-"$(id -g clickhouse)"}"
|
|
|
|
fi
|
2019-03-21 15:10:47 +00:00
|
|
|
else
|
|
|
|
USER="$(id -u)"
|
|
|
|
GROUP="$(id -g)"
|
2020-01-26 16:14:13 +00:00
|
|
|
DO_CHOWN=0
|
2019-03-21 15:10:47 +00:00
|
|
|
fi
|
2018-09-21 22:00:57 +00:00
|
|
|
|
2020-01-26 16:14:13 +00:00
|
|
|
# set some vars
|
|
|
|
CLICKHOUSE_CONFIG="${CLICKHOUSE_CONFIG:-/etc/clickhouse-server/config.xml}"
|
|
|
|
|
2018-09-21 22:00:57 +00:00
|
|
|
# get CH directories locations
|
2021-01-11 17:23:21 +00:00
|
|
|
DATA_DIR="$(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key=path || true)"
|
|
|
|
TMP_DIR="$(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key=tmp_path || true)"
|
|
|
|
USER_PATH="$(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key=user_files_path || true)"
|
|
|
|
LOG_PATH="$(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key=logger.log || true)"
|
2021-03-24 21:24:07 +00:00
|
|
|
LOG_DIR=""
|
|
|
|
if [ -n "$LOG_PATH" ]; then LOG_DIR="$(dirname "$LOG_PATH")"; fi
|
2021-01-11 17:23:21 +00:00
|
|
|
ERROR_LOG_PATH="$(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key=logger.errorlog || true)"
|
2021-03-24 21:24:07 +00:00
|
|
|
ERROR_LOG_DIR=""
|
2021-03-24 21:33:08 +00:00
|
|
|
if [ -n "$ERROR_LOG_PATH" ]; then ERROR_LOG_DIR="$(dirname "$ERROR_LOG_PATH")"; fi
|
2021-01-11 17:23:21 +00:00
|
|
|
FORMAT_SCHEMA_PATH="$(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key=format_schema_path || true)"
|
2020-05-03 20:04:00 +00:00
|
|
|
|
2022-07-08 14:13:32 +00:00
|
|
|
# There could be many disks declared in config
|
2022-08-01 10:08:32 +00:00
|
|
|
readarray -t DISKS_PATHS < <(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key='storage_configuration.disks.*.path' || true)
|
2022-09-12 21:39:16 +00:00
|
|
|
readarray -t DISKS_METADATA_PATHS < <(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key='storage_configuration.disks.*.metadata_path' || true)
|
2022-07-08 14:13:32 +00:00
|
|
|
|
2019-06-24 11:45:04 +00:00
|
|
|
CLICKHOUSE_USER="${CLICKHOUSE_USER:-default}"
|
2024-01-07 19:10:57 +00:00
|
|
|
CLICKHOUSE_PASSWORD_FILE="${CLICKHOUSE_PASSWORD_FILE:-}"
|
|
|
|
if [[ -n "${CLICKHOUSE_PASSWORD_FILE}" && -f "${CLICKHOUSE_PASSWORD_FILE}" ]]; then
|
|
|
|
CLICKHOUSE_PASSWORD="$(cat "${CLICKHOUSE_PASSWORD_FILE}")"
|
|
|
|
fi
|
2020-05-03 20:04:00 +00:00
|
|
|
CLICKHOUSE_PASSWORD="${CLICKHOUSE_PASSWORD:-}"
|
|
|
|
CLICKHOUSE_DB="${CLICKHOUSE_DB:-}"
|
2021-02-05 16:39:05 +00:00
|
|
|
CLICKHOUSE_ACCESS_MANAGEMENT="${CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT:-0}"
|
2018-09-21 22:00:57 +00:00
|
|
|
|
2024-01-19 05:00:15 +00:00
|
|
|
function create_directory_and_do_chown() {
|
|
|
|
local dir=$1
|
2019-04-10 12:29:04 +00:00
|
|
|
# check if variable not empty
|
2024-01-19 05:00:15 +00:00
|
|
|
[ -z "$dir" ] && return
|
2019-03-21 15:10:47 +00:00
|
|
|
# ensure directories exist
|
2022-08-04 11:23:45 +00:00
|
|
|
if [ "$DO_CHOWN" = "1" ]; then
|
2024-11-09 16:09:54 +00:00
|
|
|
mkdir=( mkdir )
|
2022-08-04 11:23:45 +00:00
|
|
|
else
|
2022-08-05 04:12:50 +00:00
|
|
|
# if DO_CHOWN=0 it means that the system does not map root user to "admin" permissions
|
|
|
|
# it mainly happens on NFS mounts where root==nobody for security reasons
|
|
|
|
# thus mkdir MUST run with user id/gid and not from nobody that has zero permissions
|
2024-11-09 16:09:54 +00:00
|
|
|
mkdir=( clickhouse su "${USER}:${GROUP}" mkdir )
|
2022-08-04 11:23:45 +00:00
|
|
|
fi
|
2024-11-09 16:09:54 +00:00
|
|
|
if ! "${mkdir[@]}" -p "$dir"; then
|
2019-03-21 15:10:47 +00:00
|
|
|
echo "Couldn't create necessary directory: $dir"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2020-01-26 16:14:13 +00:00
|
|
|
if [ "$DO_CHOWN" = "1" ]; then
|
2019-03-21 15:10:47 +00:00
|
|
|
# ensure proper directories permissions
|
2021-07-20 12:02:20 +00:00
|
|
|
# but skip it for if directory already has proper premissions, cause recursive chown may be slow
|
2021-07-20 04:16:51 +00:00
|
|
|
if [ "$(stat -c %u "$dir")" != "$USER" ] || [ "$(stat -c %g "$dir")" != "$GROUP" ]; then
|
|
|
|
chown -R "$USER:$GROUP" "$dir"
|
2021-07-20 13:10:29 +00:00
|
|
|
fi
|
2019-03-21 15:10:47 +00:00
|
|
|
fi
|
2024-01-19 05:00:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
create_directory_and_do_chown "$DATA_DIR"
|
|
|
|
|
|
|
|
# Change working directory to $DATA_DIR in case there're paths relative to $DATA_DIR, also avoids running
|
|
|
|
# clickhouse-server at root directory.
|
|
|
|
cd "$DATA_DIR"
|
|
|
|
|
|
|
|
for dir in "$ERROR_LOG_DIR" \
|
|
|
|
"$LOG_DIR" \
|
|
|
|
"$TMP_DIR" \
|
|
|
|
"$USER_PATH" \
|
|
|
|
"$FORMAT_SCHEMA_PATH" \
|
|
|
|
"${DISKS_PATHS[@]}" \
|
|
|
|
"${DISKS_METADATA_PATHS[@]}"
|
|
|
|
do
|
|
|
|
create_directory_and_do_chown "$dir"
|
2019-03-21 15:10:47 +00:00
|
|
|
done
|
|
|
|
|
2020-05-03 20:04:00 +00:00
|
|
|
# if clickhouse user is defined - create it (user "default" already exists out of box)
|
2022-12-29 20:09:44 +00:00
|
|
|
if [ -n "$CLICKHOUSE_USER" ] && [ "$CLICKHOUSE_USER" != "default" ] || [ -n "$CLICKHOUSE_PASSWORD" ] || [ "$CLICKHOUSE_ACCESS_MANAGEMENT" != "0" ]; then
|
2020-05-04 08:30:05 +00:00
|
|
|
echo "$0: create new user '$CLICKHOUSE_USER' instead 'default'"
|
|
|
|
cat <<EOT > /etc/clickhouse-server/users.d/default-user.xml
|
2021-10-25 18:15:42 +00:00
|
|
|
<clickhouse>
|
2021-09-22 00:22:57 +00:00
|
|
|
<!-- Docs: <https://clickhouse.com/docs/en/operations/settings/settings_users/> -->
|
2020-05-04 07:11:35 +00:00
|
|
|
<users>
|
|
|
|
<!-- Remove default user -->
|
|
|
|
<default remove="remove">
|
|
|
|
</default>
|
|
|
|
|
|
|
|
<${CLICKHOUSE_USER}>
|
|
|
|
<profile>default</profile>
|
|
|
|
<networks>
|
|
|
|
<ip>::/0</ip>
|
|
|
|
</networks>
|
2024-09-05 14:55:56 +00:00
|
|
|
<password><![CDATA[${CLICKHOUSE_PASSWORD//]]>/]]]]><![CDATA[>}]]></password>
|
2020-05-04 07:11:35 +00:00
|
|
|
<quota>default</quota>
|
2021-02-05 16:39:05 +00:00
|
|
|
<access_management>${CLICKHOUSE_ACCESS_MANAGEMENT}</access_management>
|
2020-05-04 07:11:35 +00:00
|
|
|
</${CLICKHOUSE_USER}>
|
|
|
|
</users>
|
2021-10-25 18:15:42 +00:00
|
|
|
</clickhouse>
|
2020-05-03 20:04:00 +00:00
|
|
|
EOT
|
|
|
|
fi
|
|
|
|
|
2024-02-09 13:50:50 +00:00
|
|
|
CLICKHOUSE_ALWAYS_RUN_INITDB_SCRIPTS="${CLICKHOUSE_ALWAYS_RUN_INITDB_SCRIPTS:-}"
|
|
|
|
|
2023-06-08 16:51:50 +00:00
|
|
|
# checking $DATA_DIR for initialization
|
2023-06-29 12:59:22 +00:00
|
|
|
if [ -d "${DATA_DIR%/}/data" ]; then
|
2023-06-08 16:51:50 +00:00
|
|
|
DATABASE_ALREADY_EXISTS='true'
|
|
|
|
fi
|
2018-11-28 19:55:34 +00:00
|
|
|
|
2024-02-09 13:50:50 +00:00
|
|
|
# run initialization if flag CLICKHOUSE_ALWAYS_RUN_INITDB_SCRIPTS is not empty or data directory is empty
|
|
|
|
if [[ -n "${CLICKHOUSE_ALWAYS_RUN_INITDB_SCRIPTS}" || -z "${DATABASE_ALREADY_EXISTS}" ]]; then
|
|
|
|
RUN_INITDB_SCRIPTS='true'
|
|
|
|
fi
|
|
|
|
|
2024-02-14 16:39:22 +00:00
|
|
|
if [ -n "${RUN_INITDB_SCRIPTS}" ]; then
|
2023-06-08 16:51:50 +00:00
|
|
|
if [ -n "$(ls /docker-entrypoint-initdb.d/)" ] || [ -n "$CLICKHOUSE_DB" ]; then
|
|
|
|
# port is needed to check if clickhouse-server is ready for connections
|
|
|
|
HTTP_PORT="$(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key=http_port --try)"
|
|
|
|
HTTPS_PORT="$(clickhouse extract-from-config --config-file "$CLICKHOUSE_CONFIG" --key=https_port --try)"
|
|
|
|
|
|
|
|
if [ -n "$HTTP_PORT" ]; then
|
|
|
|
URL="http://127.0.0.1:$HTTP_PORT/ping"
|
|
|
|
else
|
|
|
|
URL="https://127.0.0.1:$HTTPS_PORT/ping"
|
2021-01-11 17:23:21 +00:00
|
|
|
fi
|
2020-05-04 07:11:35 +00:00
|
|
|
|
2023-06-08 16:51:50 +00:00
|
|
|
# Listen only on localhost until the initialization is done
|
2024-11-09 16:09:54 +00:00
|
|
|
clickhouse su "${USER}:${GROUP}" clickhouse-server --config-file="$CLICKHOUSE_CONFIG" -- --listen_host=127.0.0.1 &
|
2023-06-08 16:51:50 +00:00
|
|
|
pid="$!"
|
2020-05-04 07:11:35 +00:00
|
|
|
|
2023-06-08 16:51:50 +00:00
|
|
|
# check if clickhouse is ready to accept connections
|
|
|
|
# will try to send ping clickhouse via http_port (max 1000 retries by default, with 1 sec timeout and 1 sec delay between retries)
|
|
|
|
tries=${CLICKHOUSE_INIT_TIMEOUT:-1000}
|
|
|
|
while ! wget --spider --no-check-certificate -T 1 -q "$URL" 2>/dev/null; do
|
|
|
|
if [ "$tries" -le "0" ]; then
|
|
|
|
echo >&2 'ClickHouse init process failed.'
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
tries=$(( tries-1 ))
|
|
|
|
sleep 1
|
|
|
|
done
|
2020-05-04 07:27:57 +00:00
|
|
|
|
2023-06-08 16:51:50 +00:00
|
|
|
clickhouseclient=( clickhouse-client --multiquery --host "127.0.0.1" -u "$CLICKHOUSE_USER" --password "$CLICKHOUSE_PASSWORD" )
|
2019-06-24 11:45:04 +00:00
|
|
|
|
2018-11-28 19:55:34 +00:00
|
|
|
echo
|
|
|
|
|
2023-06-08 16:51:50 +00:00
|
|
|
# create default database, if defined
|
|
|
|
if [ -n "$CLICKHOUSE_DB" ]; then
|
|
|
|
echo "$0: create database '$CLICKHOUSE_DB'"
|
|
|
|
"${clickhouseclient[@]}" -q "CREATE DATABASE IF NOT EXISTS $CLICKHOUSE_DB";
|
|
|
|
fi
|
|
|
|
|
|
|
|
for f in /docker-entrypoint-initdb.d/*; do
|
|
|
|
case "$f" in
|
|
|
|
*.sh)
|
|
|
|
if [ -x "$f" ]; then
|
|
|
|
echo "$0: running $f"
|
|
|
|
"$f"
|
|
|
|
else
|
|
|
|
echo "$0: sourcing $f"
|
|
|
|
# shellcheck source=/dev/null
|
|
|
|
. "$f"
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
*.sql) echo "$0: running $f"; "${clickhouseclient[@]}" < "$f" ; echo ;;
|
|
|
|
*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${clickhouseclient[@]}"; echo ;;
|
|
|
|
*) echo "$0: ignoring $f" ;;
|
|
|
|
esac
|
|
|
|
echo
|
|
|
|
done
|
|
|
|
|
|
|
|
if ! kill -s TERM "$pid" || ! wait "$pid"; then
|
|
|
|
echo >&2 'Finishing of ClickHouse init process failed.'
|
|
|
|
exit 1
|
|
|
|
fi
|
2018-11-28 19:55:34 +00:00
|
|
|
fi
|
2023-06-08 16:51:50 +00:00
|
|
|
else
|
|
|
|
echo "ClickHouse Database directory appears to contain a database; Skipping initialization"
|
2018-11-28 19:55:34 +00:00
|
|
|
fi
|
2018-11-26 00:26:48 +00:00
|
|
|
|
|
|
|
# if no args passed to `docker run` or first argument start with `--`, then the user is passing clickhouse-server arguments
|
|
|
|
if [[ $# -lt 1 ]] || [[ "$1" == "--"* ]]; then
|
2021-07-23 19:29:40 +00:00
|
|
|
# Watchdog is launched by default, but does not send SIGINT to the main process,
|
|
|
|
# so the container can't be finished by ctrl+c
|
|
|
|
CLICKHOUSE_WATCHDOG_ENABLE=${CLICKHOUSE_WATCHDOG_ENABLE:-0}
|
|
|
|
export CLICKHOUSE_WATCHDOG_ENABLE
|
2023-02-14 08:49:05 +00:00
|
|
|
|
2024-11-09 16:09:54 +00:00
|
|
|
# This replaces the shell script with the server:
|
|
|
|
exec clickhouse su "${USER}:${GROUP}" clickhouse-server --config-file="$CLICKHOUSE_CONFIG" "$@"
|
2018-11-26 00:26:48 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
# Otherwise, we assume the user want to run his own process, for example a `bash` shell to explore this image
|
|
|
|
exec "$@"
|