diff --git a/Dockerfile b/Dockerfile index 51131f2..df09141 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,27 @@ -FROM eclipse-temurin:17-jre +FROM --platform=linux/amd64 swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/eclipse-temurin:17-jre ENV LANG=C.UTF-8 ENV LC_ALL=C.UTF-8 ENV TZ=Asia/Shanghai ENV JAVA_OPTS="" -ENV EASYFLOW_JAR_PATH=/app/easyflow.jar +ENV EASYFLOW_JAR_PATH=/app/artifacts/easyflow.jar ENV EASYFLOW_CONFIG_PATH=file:/app/application.yml ENV EASYFLOW_LOG_FILE=/app/logs/app.log +ENV EASYFLOW_JAR_RESTART_GRACE_SECONDS=30 WORKDIR /app RUN useradd --system --create-home easyflow && \ apt-get update && \ - apt-get install -y --no-install-recommends python3 && \ + apt-get install -y --no-install-recommends python3 inotify-tools tini && \ rm -rf /var/lib/apt/lists/* && \ - mkdir -p /app/logs && \ + mkdir -p /app/logs /app/artifacts /app/data && \ chown -R easyflow:easyflow /app -USER easyflow +COPY docker-entrypoint.sh /usr/local/bin/easyflow-entrypoint.sh +RUN chmod 755 /usr/local/bin/easyflow-entrypoint.sh -VOLUME ["/app/logs"] +VOLUME ["/app/logs", "/app/data"] EXPOSE 8111 -ENTRYPOINT ["sh", "-c", "if [ ! -f \"${EASYFLOW_JAR_PATH}\" ]; then echo \"ERROR: easyflow jar not found: ${EASYFLOW_JAR_PATH}\"; exit 1; fi; java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar \"${EASYFLOW_JAR_PATH}\" --spring.config.location=\"${EASYFLOW_CONFIG_PATH}\" --logging.file.name=\"${EASYFLOW_LOG_FILE}\""] +ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/easyflow-entrypoint.sh"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..4ec43a5 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env sh +set -eu + +JAR_PATH="${EASYFLOW_JAR_PATH:-/app/artifacts/easyflow.jar}" +CONFIG_PATH="${EASYFLOW_CONFIG_PATH:-file:/app/application.yml}" +LOG_FILE="${EASYFLOW_LOG_FILE:-/app/logs/app.log}" +RESTART_GRACE_SECONDS="${EASYFLOW_JAR_RESTART_GRACE_SECONDS:-30}" +ENTRYPOINT_PRIVS_DROPPED="${EASYFLOW_ENTRYPOINT_PRIVS_DROPPED:-0}" + +JAVA_PID="" +WATCHER_PID="" +STOP_REQUESTED=0 +RESTART_REASON_FILE="/tmp/easyflow-restart-reason" + +log() { + printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" +} + +ensure_runtime_permissions() { + for path in /app/logs /app/data; do + mkdir -p "$path" + chown -R easyflow:easyflow "$path" + done +} + +drop_privileges_if_needed() { + if [ "$(id -u)" -ne 0 ] || [ "$ENTRYPOINT_PRIVS_DROPPED" = "1" ]; then + return + fi + + ensure_runtime_permissions + export EASYFLOW_ENTRYPOINT_PRIVS_DROPPED=1 + exec setpriv --reuid=easyflow --regid=easyflow --init-groups "$0" "$@" +} + +ensure_prerequisites() { + if ! command -v inotifywait >/dev/null 2>&1; then + log "ERROR: inotifywait not found" + exit 1 + fi + + if [ ! -f "$JAR_PATH" ]; then + log "ERROR: easyflow jar not found: $JAR_PATH" + exit 1 + fi + + mkdir -p "$(dirname "$LOG_FILE")" +} + +compute_jar_digest() { + sha256sum "$JAR_PATH" | awk '{print $1}' +} + +stop_watcher() { + if [ -n "$WATCHER_PID" ] && kill -0 "$WATCHER_PID" 2>/dev/null; then + kill "$WATCHER_PID" 2>/dev/null || true + wait "$WATCHER_PID" 2>/dev/null || true + fi + WATCHER_PID="" +} + +stop_java_process() { + if [ -z "$JAVA_PID" ] || ! kill -0 "$JAVA_PID" 2>/dev/null; then + return + fi + + kill -TERM "$JAVA_PID" 2>/dev/null || true + + remaining="$RESTART_GRACE_SECONDS" + while kill -0 "$JAVA_PID" 2>/dev/null; do + if [ "$remaining" -le 0 ]; then + log "java process did not stop within ${RESTART_GRACE_SECONDS}s, forcing shutdown" + kill -KILL "$JAVA_PID" 2>/dev/null || true + break + fi + sleep 1 + remaining=$((remaining - 1)) + done +} + +handle_shutdown() { + STOP_REQUESTED=1 + printf '%s' "shutdown" >"$RESTART_REASON_FILE" + stop_watcher + stop_java_process +} + +trap 'handle_shutdown' TERM INT + +start_java() { + log "starting jar: $JAR_PATH" + # JAVA_OPTS needs shell word splitting to preserve user-provided JVM args. + # shellcheck disable=SC2086 + java ${JAVA_OPTS:-} -Djava.security.egd=file:/dev/./urandom -jar "$JAR_PATH" \ + --spring.config.location="$CONFIG_PATH" \ + --logging.file.name="$LOG_FILE" & + JAVA_PID=$! +} + +start_watcher() { + jar_digest="$1" + jar_dir="$(dirname "$JAR_PATH")" + jar_name="$(basename "$JAR_PATH")" + + ( + while true; do + event_line="$(inotifywait --quiet --event close_write,moved_to --format '%e %f' "$jar_dir")" || exit 0 + event_name="${event_line%% *}" + event_file="${event_line#* }" + + if [ "$event_file" != "$jar_name" ]; then + continue + fi + + if [ ! -f "$JAR_PATH" ]; then + continue + fi + + new_digest="$(compute_jar_digest)" + if [ "$new_digest" = "$jar_digest" ]; then + continue + fi + + log "detected jar update (${event_name}), restarting java process" + printf '%s' "jar_changed" >"$RESTART_REASON_FILE" + stop_java_process + exit 0 + done + ) & + + WATCHER_PID=$! +} + +main() { + drop_privileges_if_needed "$@" + ensure_prerequisites + + current_digest="$(compute_jar_digest)" + + while true; do + rm -f "$RESTART_REASON_FILE" + start_java + start_watcher "$current_digest" + + set +e + wait "$JAVA_PID" + java_status=$? + set -e + + stop_watcher + JAVA_PID="" + + restart_reason="" + if [ -f "$RESTART_REASON_FILE" ]; then + restart_reason="$(cat "$RESTART_REASON_FILE")" + rm -f "$RESTART_REASON_FILE" + fi + + if [ "$STOP_REQUESTED" -eq 1 ] || [ "$restart_reason" = "shutdown" ]; then + exit 0 + fi + + if [ "$restart_reason" = "jar_changed" ]; then + ensure_prerequisites + current_digest="$(compute_jar_digest)" + log "restarting java with updated jar" + continue + fi + + log "java process exited unexpectedly with code $java_status" + exit "$java_status" + done +} + +main "$@" diff --git a/easyflow-ui-admin/app/.env.production b/easyflow-ui-admin/app/.env.production index f939413..a273068 100644 --- a/easyflow-ui-admin/app/.env.production +++ b/easyflow-ui-admin/app/.env.production @@ -1,7 +1,7 @@ -VITE_BASE=/ +VITE_BASE=/flow/ # 接口地址 -VITE_GLOB_API_URL= +VITE_GLOB_API_URL=/flow # 是否开启压缩,可以设置为 none, brotli, gzip VITE_COMPRESS=none