Jenkins über Apache reverse Proxy -> agents können sich nicht verbinden

sascha-sphw

Member
Hi,

ich spiele schon eine Weile (ca. 2 Tage) herum und bekomme es einfach nicht zum laufen.
Hier mal mein Setup:
Ich habe Jenkins auf einem Server welcher über den Port 8080 das Webinterface anbietet (nur im internen Subnetz erreichbar, Public über die Firewall blockiert). Der Apache im gleichen Subnetz hat eine reverse Proxy Einstellung wie hier beschrieben. Funktioniert soweit auch alles.
general-setup-apache-jenkins.png


Jetzt brauche ich aber für Jenkins externe Unterstützung bei ein paar build jobs. Diese will ich über AWS EC2 und dem Amazon EC2 Plugin für Jenkins realisieren.
Die neue Jenkins Instanz lädt sich dann den agent und die Konfiguration vom main herunter. Das funktioniert ebenfalls.
download-agent-and-jnlp.png


Das Problem ist aber, das der agent über den Port 9090 mit dem main kommunizieren möchte. Jetzt landet man aber über sub.domain.tld:9090 auf dem Server auf dem der Apache läuft und nicht auf dem Jenkins (main). Jetzt hatte ich hier ebenfalls ein reverse proxy eingestellt aber leider ohne Erfolg.
agent-communication-over-proxy.png


Vermutlich geht es einfach nicht (https://stackoverflow.com/questions...behind-nginx-reverse-proxy-for-jnlp-slaves-to).
Durch diesen Artikel bin ich aber auf die Tunnel Settings gekommen, wenn ich also händisch eine neue Node in Jenkins anlege kann ich den Tunnel auf die Public IP des Jenkin (main) setzen. Im Jenkins (main) noch den Port 9090 aufmachen. Et voilà!
Die Tunnel Einstellung wird dem agent über die slave-agent.jnlp Datei bekannt gemacht.
agent-communication-over-tunnel.png


ABER! Wie gesagt händisch. Jetzt funktioniert das Amazon EC2 Plugin aber so, dass man images (AMIs über die AWS Konsole) Vorkonfiguriert und abspeichert, sodass das Plugin diese dann bei Bedarf startet, eine Node in Jenkins konfiguriert und sich dann der agent automatisch zum Jenkins (main) verbindet.
Dazu habe ich ein PowerShell Skript geschrieben welches beim System Start ausgeführt wird.
Code:
$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT –Uri http://169.254.169.254/latest/api/token
$userData = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token" = $token} -Method GET -Uri http://169.254.169.254/latest/user-data

$jenkinsUrl = ""
$slaveName = ""
$jenkinsUser = "<your-user>"
$jenkinsUserToken = "<your-user-token>"

$userData.Split("&") | ForEach {
    $args = $_.Split("=")

    if($args[0].Equals("JENKINS_URL")) {
        $jenkinsUrl = $args[1]
        if(!($jenkinsUrl -match '/$')) {
            $jenkinsUrl = $jenkinsUrl + "/"
        }
    }
    if($args[0].Equals("SLAVE_NAME")) {
        $slaveName = $args[1]
    }
}

$url = $jenkinsUrl + "jnlpJars/agent.jar"
Invoke-WebRequest -Uri $url -OutFile ".\agent.jar"

C:\java_jdks\jdk-16.0.1+9\bin\java -jar .\agent.jar -jnlpUrl ($jenkinsUrl + "computer/" + $slaveName + "/slave-agent.jnlp") -jnlpCredentials ($jenkinsUser + ":" + $jenkinsUserToken)
Das Skript funktioniert, das habe ich über einen launch des AMIs erfolgreich testen können.

Jetzt habe ich leider keine Einstellung in dem Amazon EC2 Plugin finden können, die es mir erlaubt diese Tunnel Einstellung zu setzen. Ich habe auch schon überlegt, ob ich nicht Jenkins selbst SSL abhandeln lassen soll und die Domain über DNS dann gleich auf diesen Server zeigen lasse. Ich müsste dann aber bei einem Zertifikats update mehr als nur einen Server mit dem Zertifikat updaten. Das war ja auch der Grund für einen Apache vor allen Applikationen, um das nur an einer Stelle machen zu müssen.

Ich könnte auch das Skript anpassen, dass es die jnlp Datei zuerst lädt und die Fehlende Tunnel Einstellung selbst hinzufügt, bevor die Datei dann dem agent übergeben wird.

Hat das ggf. schon mal jemand gemacht und kann mir Tipps geben wie ich das am besten lösen könnte. Oder ggf. ist mein Setup totaler Mist und man macht das eh ganz anders.

Danke Euch im Voraus!
 

d4f

Kaffee? Wo?
Laut einer der Antworten in deinem Link ist es mittlerweile möglich :)

Allerdings redet der Stackoverflow TE aber von HTTP-proxy - die einfachere Lösung unter Berücksichtigung aller Beschränkungen wie 'falsche' Source-IP wäre aber ein TCP-Layer Proxy.

Ich kann etwas Lästern nicht lassen, hier hätte dir dein Kubernetes geholfen da es von Natur aus NodePorts und (HTTP) Router auf der gleichen Public-IP ermöglicht :p
 

sascha-sphw

Member
Laut einer der Antworten in deinem Link ist es mittlerweile möglich :)
Das werde ich mir mal anschauen, Danke! Das habe ich komplett ignoriert...
Allerdings redet der Stackoverflow TE aber von HTTP-proxy - die einfachere Lösung unter Berücksichtigung aller Beschränkungen wie 'falsche' Source-IP wäre aber ein TCP-Layer Proxy.
Das werde ich mir auch noch genauer anschauen.

Ich kann etwas Lästern nicht lassen, hier hätte dir dein Kubernetes geholfen da es von Natur aus NodePorts und (HTTP) Router auf der gleichen Public-IP ermöglicht :p
Da bin ich mir nicht so sicher. Ich habe ja meinen Jenkins in der Hetzner cloud und dort spiele ich auch gerade mit Kubernetes herum. Aber für die Jenkins Nodes brauche ich zwingend AWS EC2 (nur dort gibt es macOS Instanzen (only us region)), daher würde ich gleich alle dort machen. Aber bitte korrigieren mich wenn ich mich irre.
 

d4f

Kaffee? Wo?
Aber bitte korrigieren mich wenn ich mich irre.
Ich meinte eher dass dei Jenkins-Server und der Apache auf dem gleichen Kubernetes-Host erreichbar sein könnten, egal auf welchen Nodes sie real liegen. Der Router macht HTTP(s)-Verkehr auf allen Nodes erreichbar, der NodePort Service deinen TCP-Verkehr.
Natürlich wäre es noch immer empfehlenswert einen (Haproxy) Loadbalancer vor deinen Kubernetes zu setzen damit man nie direkt mit einem Node kommuniziert, aber das ist ein Detail =)
 

sascha-sphw

Member
Ahh, jetzt hats klick gemacht. Ich mach jetzt aber doch nochmal schnell eine statische Verdrahtung (muss ja alles schnell gehen...), werde mich dann aber unverzüglich wieder auf das Kubernetes Thema stürzen.

Danke Dir!
 
Top