Cmak: How to use KM behind a proxy?

Created on 29 Mar 2016  路  23Comments  路  Source: yahoo/CMAK

I'd like to use KM behind Nginx proxy with the app root path different from /. What should I do to fix all thoserouting? Nginx config might read as,

location /kafka-manager/ {
proxy_pass http://localhost:9000/;
}

Most helpful comment

To be honest, I think the best way would be to have a configuration value for this or maybe the whole base-url.

This would allow existing users to work without the new context and other could just turn it on.
I didnt know scala but I a sure that there are ways to archive this without much additional effort.

All 23 comments

Thank you. But that's not enough. Lots of requests from browser still reference to / which make server side routing really difficult. Lots of code need to eliminate the absolute path.

Same problem on Apache. The vassets and webjars directrories can be mapped but the application itself uses hardcoded / as link target (if you click on cluster->list) or /addCluster (if you click on cluster->add) and i am sure that all other action will use / as target :(

Because I use the same apache as reverseproxy for many tools (complete mesos cluster administration) I cannot map all requests to kafka.

I will try to play around with some rewrite rules dependant of the refferer (uuhhh....)

Lots of rewrite rules to be made. They might interfere with other services. Will spend more time to dig into codes.

Spent some more time and found a cure:

1, Modify all routes in the conf/routes by adding desired routing, /kafka-manager as below. This will force both FE and BE code running under /kafka-manager/.

GET         /kafka-manager/                                             controllers.Application.index
GET         /kafka-manager/clusters/:c                                  controllers.Cluster.cluster(c:String)
GET         /kafka-manager/clusters/:c/topics                           controllers.Topic.topics(c:String)
GET         /kafka-manager/clusters/:c/topics/addPartitions             controllers.Topic.addPartitionsToMultipleTopics(c:String)

# Versioned Assets
GET         /kafka-manager/vassets/*file          controllers.Assets.versioned(path="/public", file: Asset)

# Unversioned Assets
GET         /kafka-manager/assets/*file           controllers.Assets.at(path="/public", file)

# WebJars
GET         /kafka-manager/webjars/*file          controllers.WebJarAssets.at(file)
  1. Nginx is configured as below.
server {
        ......
        location /kafka-manager/ {
                proxy_pass http://localhost:9001/kafka-manager/;
                proxy_connect_timeout   2;
                proxy_redirect off;
                proxy_buffering off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

Now enjoy your KM at /kafka-manager/

Might consider defaulting everything to /kafka-manager/*. Let me think about it, don't want to impact existing users.

To be honest, I think the best way would be to have a configuration value for this or maybe the whole base-url.

This would allow existing users to work without the new context and other could just turn it on.
I didnt know scala but I a sure that there are ways to archive this without much additional effort.

The best way would be to make KM a webapplication (a WAR see request #166 ) This way everything can be relative to the context (that can be renamed) and it's also trivial to integrate it correctly with NginX or Apache.

@dwu-zingbox

I have tried your solution with the routes file and it didnt work for me. Is there anything else that need to be changed?

I tried both variants (just adding the custom file to container and building with the customized file) without any success

@hotstepper13

A few thing you can double check,

  1. Did you compile it again after modifying the routes file?
    2, If the modified routes works, you should be able to see if at <your_server>:<km_port>/your_route/ first.
  2. Open the dev mode of your browser and see if any link returns 404.
  3. If your KM works fine on its port with the new routing. Try curl through your proxy and see what the first page you can get

Good luck

@dwu-zingbox
That for your reply. I use Docker to server the application.
I have created a modified routes file.

The process is, Download and extract the sources from master, overwrite the routes file with the modified one, start the sbt script.

I choose the prefix /kafka/ for my services.

The process is based on https://github.com/sheepkiller/kafka-manager-docker/blob/master/Dockerfile and the only change is that i add my custom routes file which makes it look like:

ENV ZK_HOSTS=localhost:2181 \
    KM_VERSION=1.3.0.7 \
    KM_REVISION=4b57fc9b65e6f9ac88fff4391994fd06bb782663 \
    KM_CONFIGFILE="conf/application.conf"

COPY routes /ttt/

RUN apk --update add --no-cache git bash && \
    mkdir -p /tmp && \
    cd /tmp && \
    git clone https://github.com/yahoo/kafka-manager && \
    cd /tmp/kafka-manager && \
    git checkout ${KM_REVISION} && \
    cp /ttt/routes /tmp/kafka-manager/conf/ && \
    echo 'scalacOptions ++= Seq("-Xmax-classfile-name", "200")' >> build.sbt && \
    ./sbt clean dist && \
    unzip  -d / ./target/universal/kafka-manager-${KM_VERSION}.zip && \
    rm -fr /tmp/* /root/.sbt /root/.ivy2 && \
    printf '#!/bin/sh\nexec ./bin/kafka-manager -Dconfig.file=${KM_CONFIGFILE} "${KM_ARGS}" "${@}"\n' > /kafka-manager-${KM_VERSION}/km.sh && \
    chmod +x /kafka-manager-${KM_VERSION}/km.sh && \
    rm -fr /kafka-manager-${KM_VERSION}/share \
    apk del git

I can see that my modified routes finally ended up in /kafka-manager-1.3.0.7/conf and contain my changes. Therefore it looks as it would be used. But as i access the application, it says "action not found "For request 'GET /kafka/'"

[UPDATE]
While debugging this i found a variable prefix that seems to be available in the routes files. I found a scala file that will be generated out of the routes. However I have no clue how to set it. For now I try a different approach in building outside of docker without any additional scala properties and then add the build zip file to the container. Maybe this will help.

[UPDATE2]
nah, it didnt work. But it looks like as if i have a problem with my kafka installation as it seems to report the containerid as hostname. This leads to rmi exceptions within kafka-manager. I will try to fix that first.

[UPDATE3]
Nevermind... it was my fault. The image I ran on the server was not properly updated. It is working as expected with your tipps. Thank you very much!

@hotstepper13
Glad you sorted it out. I also tried your idea and it worked fine for me. Only difference is that I broke the RUN command into two pieces and insert COPY command to use customized routes and application.conf file.

FROM centos:7

MAINTAINER Clement Laforet <[email protected]>

RUN yum update -y && \
    yum install -y git wget unzip which && \
    yum clean all

ENV JAVA_MAJOR=8 \
    JAVA_UPDATE=73 \
    JAVA_BUILD=02 

RUN wget -nv --no-cookies --no-check-certificate \
    --header "Cookie: oraclelicense=accept-securebackup-cookie" \
    "http://download.oracle.com/otn-pub/java/jdk/${JAVA_MAJOR}u${JAVA_UPDATE}-b${JAVA_BUILD}/jdk-${JAVA_MAJOR}u${JAVA_UPDATE}-linux-x64.rpm" -O /tmp/jdk-${JAVA_MAJOR}u${JAVA_UPDATE}-linux-x64.rpm && \
     yum localinstall -y /tmp/jdk-${JAVA_MAJOR}u${JAVA_UPDATE}-linux-x64.rpm && \
     rm -f /tmp/jdk-${JAVA_MAJOR}u${JAVA_UPDATE}-linux-x64.rpm

ENV JAVA_HOME=/usr/java/jdk1.8.0_${JAVA_UPDATE} \
#    ZK_HOSTS=localhost:2181 \
    KM_VERSION=1.3.0.7 \
    KM_REVISION=4b57fc9b65e6f9ac88fff4391994fd06bb782663 \
    KM_CONFIGFILE="conf/application.conf"

RUN mkdir -p /tmp && \
    cd /tmp && \
    git clone https://github.com/yahoo/kafka-manager && \
    cd /tmp/kafka-manager && \
    git checkout ${KM_REVISION} && \
    echo 'scalacOptions ++= Seq("-Xmax-classfile-name", "200")' >> build.sbt

COPY routes /tmp/kafka-manager/conf
COPY application.conf /tmp/kafka-manager/conf

RUN cd /tmp/kafka-manager && \
    ./sbt clean dist && \
    unzip  -d / ./target/universal/kafka-manager-${KM_VERSION}.zip && \
    rm -fr /tmp/* /root/.sbt /root/.ivy2 && \
    printf '#!/bin/sh\nexec ./bin/kafka-manager -Dconfig.file=${KM_CONFIGFILE} "${KM_ARGS}" "${@}"\n' > /kafka-manager-${KM_VERSION}/km.sh && \
    chmod +x /kafka-manager-${KM_VERSION}/km.sh

WORKDIR /kafka-manager-${KM_VERSION}

EXPOSE 9000
ENTRYPOINT ["./km.sh"]

There is a play.http.context in Play 2.4 which seems dedicated to changing the base URL.
However in KM it's not taken into account :'( , adding this to application.conffile doesn't help:

play.http.context="/kafka-manager/"

https://github.com/playframework/playframework/issues/4084

Hi, I am struggling on the same thing. Though changing conf/routes works for cases where base url is static, my base url is kind of dynamic like /kafka-manager/ , where id is provided at run time that means i cannot compile the code everytime.

Is there anything I can do to unblock this situation.? @dwu-zingbox @hotstepper13

This fixed since PR #249 you can configure context path with play.http.context config

@gquintana I had tried that. I am running KM behind a proxy server which is reachable via curl call. When I add the relative path to above field, my call to access KM fails with:

java.net.MalformedURLException: unknown protocol: data

without that field, the curl call is succeeding but KM is not working. So I am kind of stuck.
Is there any other setting I need to set.?
Have you ever seen this behaviour? or can help me out on this?

@ashishsachdeva To make myself clearer, with default configuration you can do:

curl http://localhost:9000/api/status/clusters

After setting in application.conf:

play.http.context = "/kafka-manager/"

you can do instead

http://localhost:9000/kafka-manager/api/status/clusters

@gquintana I have understood this part.. what I am saying is, after changing this settings: play.http.context = "/kafka-manager/"

my curl call has started to throw exception:
java.net.MalformedURLException: unknown protocol: data

thats where I am kind of stuck at and asking if there is any other setting or something I am missing.?

I'm running into this on KM 1.3.3.14 (Play 2.4.6). I've tried the following, but nothing works. There are several requests still hitting the root path (example: /webjars/bootstrap/3.3.5/css/bootstrap.min.css).

  • -Dplay.http.context=/kafka-manager
  • -Dplay.http.context=/kafka-manager/
  • -Dapplication.context=/kafka-manager
  • -Dapplication.context=/kafka-manager/

cc https://github.com/playframework/playframework/issues/4084#issuecomment-199470315

Got it working with -Dplay.http.context=/kafka-manager. I had a LB rewrite rule that was stripping off the /kafka-manager path when proxying.

@gquintana :+1: Works like a charm with adjusting play.http.context = "/kafka-manager/".

Was this page helpful?
0 / 5 - 0 ratings

Related issues

BDeus picture BDeus  路  5Comments

josephfrancis picture josephfrancis  路  5Comments

jmax01 picture jmax01  路  4Comments

tanuj83 picture tanuj83  路  5Comments

lazystone picture lazystone  路  4Comments