如何将自定义脚本嵌入provectuslabs/kafka-ui镜像并解决执行问题
Kafka UI + Docker Swarm Secrets 配置问题解决
问题背景
使用provectuslabs/kafka-ui:v0.7.1镜像,想通过自定义脚本读取Docker Swarm Secrets(路径/run/secrets/),把形如DOCKER-SECRET->kafka_ui_user的模板变量替换为真实密钥值。过程中遇到两个问题:
- 启动容器时报错
exec /script.sh: no such file or directory - 安装bash后脚本能运行,但Kafka UI依旧使用Compose里的模板变量,不识别转换后的环境变量
初始Dockerfile:
FROM provectuslabs/kafka-ui:v0.7.1 USER root COPY script.sh /script.sh RUN chmod +x /script.sh EXPOSE 8080 ENTRYPOINT ["/script.sh"] CMD ["/bin/sh" "-c" "java --add-opens java.rmi/javax.rmi.ssl=ALL-UNNAMED $JAVA_OPTS -jar kafka-ui-api.jar"]
自定义密钥解析脚本script.sh:
#!/bin/bash env_secret_expand() { var="$1" eval val=\$$var if secret_name=$(expr match "$val" "DOCKER-SECRET->\([^}]\+\)$"); then secret="${ENV_SECRETS_DIR}/${secret_name}" if [ -f "$secret" ]; then val=$(cat "${secret}") export "$var"="$val" fi fi } env_secrets_expand() { for env_var in $(printenv | cut -f1 -d"=") do env_secret_expand $env_var done } env_secrets_expand
添加RUN apk add --no-cache bash后脚本可运行,但变量替换未生效。
解决方案
1. 解决脚本找不到的错误
报错原因是镜像默认使用ash shell,而脚本指定了#!/bin/bash但镜像未安装bash。两种修复方式:
- 在Dockerfile中添加
RUN apk add --no-cache bash(已做) - 或者把脚本的shebang改为
#!/bin/sh(需确保脚本语法兼容ash)
2. 确保Kafka UI读取替换后的环境变量
核心问题是当前脚本执行完后没有正确启动Kafka UI,导致新环境变量没被JVM进程继承。需要修改脚本和Dockerfile的ENTRYPOINT/CMD配置:
步骤1:更新脚本script.sh
在脚本末尾添加命令执行逻辑,保证信号能传递到Kafka UI进程:
#!/bin/bash env_secret_expand() { var="$1" eval val=\$$var if secret_name=$(expr match "$val" "DOCKER-SECRET->\([^}]\+\)$"); then # 设置默认Secrets路径,避免依赖环境变量 secret="${ENV_SECRETS_DIR:-/run/secrets}/${secret_name}" if [ -f "$secret" ]; then val=$(cat "${secret}") export "$var"="$val" fi fi } env_secrets_expand() { for env_var in $(printenv | cut -f1 -d"=") do env_secret_expand $env_var done } env_secrets_expand # 执行后续启动命令,用exec替换当前shell,保证信号传递 exec "$@"
步骤2:修正Dockerfile
调整CMD格式,避免使用sh -c(会创建子shell,导致环境变量传递问题):
FROM provectuslabs/kafka-ui:v0.7.1 USER root # 安装bash以支持脚本 RUN apk add --no-cache bash COPY script.sh /script.sh RUN chmod +x /script.sh EXPOSE 8080 ENTRYPOINT ["/script.sh"] # 使用数组格式传递启动命令,直接启动JVM CMD ["java", "--add-opens", "java.rmi/javax.rmi.ssl=ALL-UNNAMED", "-jar", "kafka-ui-api.jar"]
关键要点
exec "$@"会把ENTRYPOINT后的CMD参数作为当前进程执行,确保Kafka UI能继承脚本设置的环境变量,同时接收Docker的停止信号- 去掉
sh -c包装,直接用java命令的数组格式,避免环境变量在子shell中丢失 - 给
ENV_SECRETS_DIR设置默认值/run/secrets,增强脚本鲁棒性
内容的提问来源于stack exchange,提问作者Михаил Васильев
相关产品推荐
相关产品推荐

