From 67bf187d99da2251e05d3291d535dddacd06b10b Mon Sep 17 00:00:00 2001 From: Alisa Date: Sun, 12 May 2024 11:41:42 +0800 Subject: [PATCH] chore: docker image improvements (#1692) * feat: add --db_options command line options to set mongodb connection options * feat: use standard docker-entrypoint.sh and ENTRYPOINT * fix: make docker-compose file more generic * fix: output configurations before exec * fix: incorrect command line option for mongodb collection name --- apps/core/src/app.config.ts | 5 +- docker-compose.yml | 47 ++++---- docker-entrypoint.sh | 208 ++++++++++++++++++++++++++++++++++++ docker-run.sh | 38 ------- dockerfile | 8 +- 5 files changed, 240 insertions(+), 66 deletions(-) create mode 100755 docker-entrypoint.sh delete mode 100644 docker-run.sh diff --git a/apps/core/src/app.config.ts b/apps/core/src/app.config.ts index 81a34b08..2ac7cbe6 100644 --- a/apps/core/src/app.config.ts +++ b/apps/core/src/app.config.ts @@ -24,6 +24,7 @@ const commander = program .option('--db_port ', 'mongodb database port') .option('--db_user ', 'mongodb database user') .option('--db_password ', 'mongodb database password') + .option('--db_options ', 'mongodb database options') .option('--db_connection_string ', 'mongodb connection string') // redis .option('--redis_host ', 'redis host') @@ -122,10 +123,12 @@ export const MONGO_DB = { port: argv.db_port || 27017, user: argv.db_user || '', password: argv.db_password || '', + options: argv.db_options || '', get uri() { const userPassword = this.user && this.password ? `${this.user}:${this.password}@` : '' - return `mongodb://${userPassword}${this.host}:${this.port}/${this.dbName}` + const dbOptions = this.options ? `?${this.options}` : '' + return `mongodb://${userPassword}${this.host}:${this.port}/${this.dbName}${dbOptions}` }, customConnectionString: argv.db_connection_string, } diff --git a/docker-compose.yml b/docker-compose.yml index 51a6bb30..6350c578 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,22 +1,14 @@ -version: '3.8' - services: app: container_name: mx-server image: innei/mx-server:5 - command: bash ./docker-run.sh environment: - TZ=Asia/Shanghai - NODE_ENV=production - - ALLOWED_ORIGINS - - JWT_SECRET - - ENCRYPT_KEY - - ENCRYPT_ENABLE - - FORCE_CACHE_HEADER - - CDN_CACHE_HEADER - - THROTTLE_TTL - - THROTTLE_LIMIT - + - DB_HOST=mongo + - REDIS_HOST=redis + - ALLOWED_ORIGINS=localhost + - JWT_SECRET=YOUR_SUPER_SECURED_JWT_SECRET_STRING volumes: - ./data/mx-space:/root/.mx-space ports: @@ -24,12 +16,9 @@ services: depends_on: - mongo - redis - links: - - mongo - - redis networks: - - app-network - restart: always + - mx-space + restart: unless-stopped healthcheck: test: ['CMD', 'curl', '-f', 'http://127.0.0.1:2333/api/v2/ping'] interval: 1m30s @@ -43,16 +32,24 @@ services: volumes: - ./data/db:/data/db networks: - - app-network - restart: always - redis: - image: redis - container_name: redis + - mx-space + restart: unless-stopped + redis: + image: redis:alpine + container_name: redis + volumes: + - ./data/redis:/data + healthcheck: + test: ['CMD-SHELL', 'redis-cli ping | grep PONG'] + start_period: 20s + interval: 30s + retries: 5 + timeout: 3s networks: - - app-network - restart: always + - mx-space + restart: unless-stopped networks: - app-network: + mx-space: driver: bridge diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 00000000..6aaf1cb7 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,208 @@ +#!/bin/bash + +command_args="" + +# ======= Helper Functions ======= + +get_boolean_str() { + if [ "$1" = "true" ]; then + echo "true" + else + echo "false" + fi +} + +is_in_cmd_with_value() { + CMD_ARG=$1 + for arg in "${@:1}" + do + if [[ "$arg" == "$CMD_ARG"* ]] && [ -n "${arg#*=}" ]; then + echo "true" + return + fi + done + + echo "false" +} + +set_value() { + VAR_NAME=$1 + CMD_ARG=$2 + DEFAULT_VALUE=$3 + + # if command line argument is preset, use it + if [ "$(is_in_cmd_with_value "$CMD_ARG" ${@:3})" = "true" ]; then + command_args+=" $CMD_ARG$(get_cmd_value "$CMD_ARG" ${@:3})" + return + fi + + # if environment variable is preset, use it + if [ -n "${!VAR_NAME}" ]; then + command_args+=" $CMD_ARG${!VAR_NAME}" + return + fi + + # if default value is not '@@NULL@@', use it + if [ "$DEFAULT_VALUE" != "@@NULL@@" ]; then + command_args+=" $CMD_ARG$DEFAULT_VALUE" + fi +} + +is_in_cmd() { + CMD_ARG=$1 + for arg in "${@:2}" + do + if [[ "$arg" == "$CMD_ARG" ]]; then + echo "true" + return + fi + done + + echo "false" +} + +set_switch() { + VAR_NAME=$1 + CMD_ARG=$2 + DEFAULT_VALUE=$3 + + # if command line argument is preset, use it + if [ "$(is_in_cmd "$CMD_ARG" ${@:3})" = "true" ]; then + command_args+=" $CMD_ARG" + return + fi + + # if environment variable is preset, use it + if [ -n "${!VAR_NAME}" ]; then + if [ "${!VAR_NAME}" = "true" ]; then + command_args+=" $CMD_ARG" + fi + + return + fi + + # use default value + if [ "$DEFAULT_VALUE" = "true" ]; then + command_args+=" $CMD_ARG" + fi +} + +get_cmd_value() { + CMD_ARG=$1 + for arg in "${@:2}" + do + if [[ "$arg" == "$CMD_ARG"* ]]; then + echo "${arg#*=}" + return + fi + done + + echo "" +} + +get_mongodb_configuration() { + CMD=$@ + CONNECTION_STRING="mongodb://" + + if [ "$(is_in_cmd_with_value "--db_connection_string=" $CMD)" = "true" ]; then + CONNECTION_STRING=$(get_cmd_value "--db_connection_string=" $CMD) + else + if [ "$(is_in_cmd_with_value "--db_user=" $CMD)" = "true" ]; then + CONNECTION_STRING+="$(get_cmd_value "--db_user=" $CMD):************@" + fi + CONNECTION_STRING+="$(get_cmd_value "--db_host=" $CMD):$(get_cmd_value "--db_port=" $CMD)/$(get_cmd_value "--collection_name=" $CMD)" + if [ "$(is_in_cmd_with_value "--db_options=" $CMD)" = "true" ]; then + CONNECTION_STRING+="?$(get_cmd_value "--db_options=" $CMD)" + fi + fi + + echo $CONNECTION_STRING +} + +# ================================ + +# ======= Environment Variables ======= + +declare -A valueMap=( + [PORT]="value,--port=,2333" + [DEMO]="switch,--demo,false" + [ALLOWED_ORIGINS]="value,--allowed_origins=,localhost" + [CONFIG_PATH]="value,--config_path=,@@NULL@@" + + # DB + [DB_COLLECTION_NAME]="value,--collection_name=,mx-space" + [DB_HOST]="value,--db_host=,127.0.0.1" + [DB_PORT]="value,--db_port=,27017" + [DB_USER]="value,--db_user=,@@NULL@@" + [DB_PASSWORD]="value,--db_password=,@@NULL@@" + [DB_OPTIONS]="value,--db_options=,@@NULL@@" + [DB_CONNECTION_STRING]="value,--db_connection_string=,@@NULL@@" + + # Redis + [REDIS_HOST]="value,--redis_host=,127.0.0.1" + [REDIS_PORT]="value,--redis_port=,6379" + [REDIS_PASSWORD]="value,--redis_password=,@@NULL@@" + [DISABLE_CACHE]="switch,--disable_cache,false" + + # JWT + [JWT_SECRET]="value,--jwt_secret=,@@NULL@@" + [JWT_EXPIRE]="value,--jwt_expire=,@@NULL@@" + + # Cluster + [CLUSTER]="switch,--cluster,false" + [CLUSTER_WORKERS]="value,--cluster_workers=,@@NULL@@" + + # Debug + [DEBUG]="switch,--http_request_verbose,false" + [DEBUG_MEMORY_DUMP]="switch,--debug_memory_dump,false" + + # Cache + [CACHE_TTL]="value,--http_cache_ttl=,@@NULL@@" + [CACHE_CDN_HEADER]="switch,--http_cache_enable_cdn_header=,false" + [CACHE_FORCE_HEADER]="switch,--http_cache_enable_force_cache_header,false" + + # Security + [ENCRYPT_ENABLE]="switch,--encrypt_enable,false" + [ENCRYPT_KEY]="value,--encrypt_key=,@@NULL@@" + [ENCRYPT_ALGORITHM]="value,--encrypt_algorithm=,@@NULL@@" + + # Throttle + [THROTTLE_TTL]="value,--throttle_ttl=,@@NULL@@" + [THROTTLE_LIMIT]="value,--throttle_limit=,@@NULL@@" + + # Color + [COLOR]="switch,--color,true" +) + +for key in "${!valueMap[@]}"; do + IFS=',' read -ra tuple <<< "${valueMap[$key]}" + TYPE=${tuple[0]} + CMD_ARG=${tuple[1]} + DEFAULT=${tuple[2]} + + if [ "$TYPE" = "value" ]; then + set_value $key $CMD_ARG $DEFAULT $@ + elif [ "$TYPE" = "switch" ]; then + set_switch $key $CMD_ARG $DEFAULT $@ + fi + +done + +# ==================================== + +echo "Starting Mix Space" + + +echo "============== Configurations ==============" +echo "Listen Port: $(get_cmd_value "--port=" $command_args)" +echo "MongoDB: $(get_mongodb_configuration $command_args)" +echo "Redis: $(get_cmd_value "--redis_host=" $command_args):$(get_cmd_value "--redis_port=" $command_args)" +echo "Allowed Origins: $(get_cmd_value "--allowed_origins=" $command_args)" +echo "Config Path: $(if [ -z "$(get_cmd_value "--config_path=" $command_args)" ]; then echo "NULL"; else echo "$(get_cmd_value "--config_path=" $command_args)"; fi)" +echo "Encryption: $(get_boolean_str $(is_in_cmd "--encrypt_enable" $command_args))" +echo "Cluster: $(get_boolean_str $(is_in_cmd "--cluster" $command_args))" +echo "============================================" + +command="node index.js $command_args" + +exec $command diff --git a/docker-run.sh b/docker-run.sh deleted file mode 100644 index 34531880..00000000 --- a/docker-run.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -command="node index.js \ - --redis_host=redis --db_host=mongo \ - --allowed_origins=${ALLOWED_ORIGINS} \ - --jwt_secret=${JWT_SECRET} \ - --color \ - " - -if [ -n "$MONGO_CONNECTION" ]; then - command+=" --db_connection_string=${MONGO_CONNECTION}" -fi - -if [ -n "$CDN_CACHE_HEADER" ]; then - command+=" --http_cache_enable_cdn_header" -fi - -if [ -n "$FORCE_CACHE_HEADER" ]; then - command+=" --http_cache_enable_force_cache_header" -fi - -if [ -n "$ENCRYPT_KEY" ]; then - command+=" --encrypt_key=${ENCRYPT_KEY}" -fi - -if [ "$ENCRYPT_ENABLE" = "true" ]; then - command+=" --encrypt_enable " -fi - -if [ -n "$THROTTLE_TTL" ]; then - command+=" --throttle_ttl=${THROTTLE_TTL}" -fi - -if [ -n "$THROTTLE_LIMIT" ]; then - command+=" --throttle_limit=${THROTTLE_LIMIT}" -fi - -exec $command diff --git a/dockerfile b/dockerfile index 9537ba0f..34e1471d 100644 --- a/dockerfile +++ b/dockerfile @@ -14,8 +14,12 @@ RUN apk add zip unzip mongodb-tools bash fish rsync jq curl --no-cache WORKDIR /app COPY --from=builder /app/out . COPY --from=builder /app/assets ./assets -COPY ./docker-run.sh . + +COPY docker-entrypoint.sh . +RUN chmod +x docker-entrypoint.sh + ENV TZ=Asia/Shanghai EXPOSE 2333 -CMD echo "MixSpace Server Image." && sh + +ENTRYPOINT [ "./docker-entrypoint.sh" ]