diff --git a/mesos/jenkins/Dockerfile b/mesos/jenkins/Dockerfile index 3c3c5a5..f62b0c0 100644 --- a/mesos/jenkins/Dockerfile +++ b/mesos/jenkins/Dockerfile @@ -57,9 +57,6 @@ RUN chmod a+x /usr/local/bin/connect-slave.sh COPY jenkins.sh /usr/local/bin/jenkins.sh RUN chmod a+x /usr/local/bin/jenkins.sh -COPY gitconfig $JENKINS_HOME/.gitconfig -RUN chown jenkins:jenkins $JENKINS_HOME/.gitconfig - ENV REF_DIR /usr/share/jenkins/ref ADD defaults.tgz $REF_DIR COPY plugins.txt $REF_DIR/ diff --git a/mesos/jenkins/Makefile b/mesos/jenkins/Makefile index e64769a..80aeb38 100644 --- a/mesos/jenkins/Makefile +++ b/mesos/jenkins/Makefile @@ -7,7 +7,7 @@ MARATHON ?= localhost:8080 .PHONY = install push deploy clean defaults.tgz: - tar zcvf $(@) *.xml init.groovy.d/ + tar zcvf $(@) *.xml gitconfig init.groovy.d/ install: defaults.tgz docker build -t $(TAG) . diff --git a/mesos/jenkins/README.md b/mesos/jenkins/README.md index 0380127..621c417 100644 --- a/mesos/jenkins/README.md +++ b/mesos/jenkins/README.md @@ -1,8 +1,9 @@ + # Jenkins on Mesos Jenkins is deployed on Mesos using a Docker image deployed through Marathon. The image contains some basic configuration and an init script that produces a fully-functioning server, including connected build slaves, OOTB. -### Building the image +## Building the image First check out the source from GitHub so you can modify the base config to suit your deployment scenario: @@ -31,7 +32,7 @@ JWiPlEoKa1Z3c Replace the string "4Dm3fH39Geavs" in the `Dockerfile` with the output from the `openssl passwd` command. -#### Build +### Build ``` $ TAG=jenkins make clean install @@ -51,13 +52,29 @@ Step 1 : FROM jenkinsci/jenkins:2.8 ... ``` -### Deploying the image +## Deploying the image The image is deployed to Mesos with Marathon. An example `marathon.json` file exists in the source repository. The main value to change in the `marathon.json` is the env var `JENKINS_CONFIG_REPO`, which should be set to an `org/repo` where the Jenkins configuration will be backed up. If using an existing repository, know that once the Jenkins server is running, you'll have to visit the configuration page and reload everything from SCM using the provided link. -#### SSH keys + +### Running localy on marathon 127.0.0.1 + +Run ```make deploy``` + +### Running on remote marathon (other than 127.0.0.1) + +As soon as a jenkins installation with all required plugins can crash sometimes, and running on remote marathon leades to unpersistent jenkins home directory. To make the system tolerant to jenkins restart several tricks should apply. + +1 Edit ```marathon-remote.json.example``` to replace {{PERSISTENT_SLAVE_IP}} with IP of the mesos slave to use. +2 Edit ```marathon-remote.json.example``` to replace {{PERSISTENT_SLAVE_PORT}} with port number you want to use to mke URL PERSISTENT. +3 Connect with ssh to the slave you want to use for jenkins and create data only container ```jenkins-data``` with ```docker run -d -v /home/jenkins_home:/var/jenkins_home --name=jenkins-data --entrypoint=/bin/echo alpine "jenkins data-only container"``` +4 Edit ```marathon-remote.json.example``` to replace {{JENKINS_DATA_CONTAINER}} with jenkins-data +5 Replace ```marathon.json``` with ```marathon-remote.json.example``` + + +### SSH keys Note that the provided JSON assumes that slaves have a user dedicated to Jenkins named `jenkins` and that a valid SSH key (that can access source repositories on GitHub) is contained in a `.tar.gz` file located in `/home/jenkins/` and named `ssh.tar.gz`. This file will be copied into the Jenkins server's `/var/jenkins_home` directory and will be used as the SSH key when syncing configuration and checking out source code. diff --git a/mesos/jenkins/connect-slave.sh b/mesos/jenkins/connect-slave.sh index 6884fc5..109670e 100755 --- a/mesos/jenkins/connect-slave.sh +++ b/mesos/jenkins/connect-slave.sh @@ -1,7 +1,7 @@ #!/bin/bash curl -sSL -XPOST -H "Content-Type: application/json" -d @- "http://marathon.mesos:8080/v2/apps" <> "$COPY_REFERENCE_FILE_LOG" -find /usr/share/jenkins/ref/ -type f -exec bash -c "copy_reference_file '{}'" \; -sed -i "s#\${JENKINS_CONFIG_REPO}#$JENKINS_CONFIG_REPO#g" $JENKINS_HOME/scm-sync-configuration.xml -cp -R $MESOS_SANDBOX/.ssh $JENKINS_HOME/.ssh +if [ "x$USE_PERSISTENT_JENKINS_HOME" == "x" ]; then + rm -f $JENKINS_HOME/.USE_PERSISTENT_JENKINS_HOME + echo "--- Copying files at $(date)" >> "$COPY_REFERENCE_FILE_LOG" + find /usr/share/jenkins/ref/ -type f -exec bash -c "copy_reference_file '{}'" \; + sed -i "s#\${JENKINS_CONFIG_REPO}#$JENKINS_CONFIG_REPO#g" $JENKINS_HOME/scm-sync-configuration.xml + cp -R $MESOS_SANDBOX/.ssh $JENKINS_HOME/.ssh +elif [ ! -f $JENKINS_HOME/.USE_PERSISTENT_JENKINS_HOME ]; then + echo "--- Copying files at $(date)" >> "$COPY_REFERENCE_FILE_LOG" + find /usr/share/jenkins/ref/ -type f -exec bash -c "copy_reference_file '{}'" \; + sed -i "s#\${JENKINS_CONFIG_REPO}#$JENKINS_CONFIG_REPO#g" $JENKINS_HOME/scm-sync-configuration.xml + cp -R $MESOS_SANDBOX/.ssh $JENKINS_HOME/.ssh + touch $JENKINS_HOME/.USE_PERSISTENT_JENKINS_HOME +fi + +if [ [ ! -f $JENKINS_HOME/.gitconfig ] -a [ -f $JENKINS_HOME/gitconfig ] ]; then + mv -f $JENKINS_HOME/gitconfig $JENKINS_HOME/.gitconfig +fi # if `docker run` first argument start with `--` the user is passing jenkins launcher arguments if [[ $# -lt 1 ]] || [[ "$1" == "--"* ]]; then eval "exec java $JAVA_OPTS -jar /usr/share/jenkins/jenkins.war $JENKINS_OPTS \"\$@\"" -fi - +else # As argument is not jenkins, assume user want to run his own process, for sample a `bash` shell to explore this image -exec "$@" + exec "$@" +fi diff --git a/mesos/jenkins/marathon-remote.json.example b/mesos/jenkins/marathon-remote.json.example new file mode 100644 index 0000000..fe11f85 --- /dev/null +++ b/mesos/jenkins/marathon-remote.json.example @@ -0,0 +1,88 @@ +{ + "id": "/jenkins/master", + "cmd": null, + "cpus": 2, + "mem": 4096, + "disk": 0, + "instances": 1, + "constraints": [ + [ + "hostname", + "CLUSTER", + "{{PERSISTENT_SLAVE_IP}}" + ] + ], + "container": { + "type": "DOCKER", + "volumes": [ + { + "containerPath": "/var/run/docker.sock", + "hostPath": "/var/run/docker.sock", + "mode": "RW" + } + ], + "docker": { + "image": "jenkins-mesos-local", + "network": "BRIDGE", + "portMappings": [ + { + "containerPort": 8080, + "hostPort": {{PERSISTENT_SLAVE_PORT}}, + "servicePort": 10002, + "protocol": "tcp", + "labels": {} + }, + { + "containerPort": 0, + "hostPort": 0, + "servicePort": 10003, + "protocol": "tcp", + "labels": {} + } + ], + "privileged": true, + "parameters": [], + "forcePullImage": false, + "parameters": [ + { "key": "volumes-from", "value": "{{JENKINS_DATA_CONTAINER}}" } + ] + } + }, + "env": { + "JENKINS_CONFIG_REPO": "jbrisbin/jenkins-mesos-softlayer", + "JENKINS_OPTS": "--prefix=/jenkins", + "USE_PERSISTENT_JENKINS_HOME": "yes" + }, + "healthChecks": [ + { + "path": "/jenkins/", + "protocol": "HTTP", + "portIndex": 0, + "gracePeriodSeconds": 300, + "intervalSeconds": 300, + "timeoutSeconds": 300, + "maxConsecutiveFailures": 25, + "ignoreHttp1xx": false + } + ], + "portDefinitions": [ + { + "port": 10002, + "protocol": "tcp", + "labels": {} + }, + { + "port": 10003, + "protocol": "tcp", + "labels": {} + } + ], + "fetch": [ + { + "uri": "file:///home/jenkins/ssh.tar.gz", + "extract": true, + "executable": false, + "cache": false + } + ] +} \ No newline at end of file