diff --git a/bin/jenkins.sh b/bin/jenkins.sh index fb019d12..335b5867 100755 --- a/bin/jenkins.sh +++ b/bin/jenkins.sh @@ -1,6 +1,6 @@ #!/bin/bash -docker pull jenkins/jenkins:lts-alpine +docker pull jenkins/jenkins:latest-jdk21 docker compose build --pull diff --git a/docker-compose.yaml b/docker-compose.yaml index b085be7a..7925bae3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,20 +1,72 @@ -version: "3" +name: codingstyle + services: - jenkins-controller: + jenkins: + container_name: jenkins build: context: docker/images/jenkins-controller volumes: - /var/run/docker.sock:/var/run/docker.sock - - ./docker/volumes/jenkins-home:/var/jenkins_home:cached + - ./docker/volumes/jenkins-home:/var/jenkins_home # Mounts the local jenkins_home volume to the /var/jenkins_home path inside the container + - ./secrets/jcasc_token:/run/secrets/CASC_RELOAD_TOKEN:ro # Mounting the token as "container secret" makes it available in JCasc as the variable ${CASC_RELOAD_TOKEN} + - agent-ssh-dir:/ssh-dir # Mounts the shared volume agent-ssh-dir to a path inside the container ports: - 8081:8080 # Jenkins UI - HOST:CONTAINER environment: - TRY_UPGRADE_IF_NO_MARKER=true - - JAVA_OPTS= -Dstapler.jelly.noCache=true -Dhudson.remoting.ClassFilter=com.google.common.collect.ImmutableListMultimap -DexecutableWar.jetty.disableCustomSessionIdCookieName=true -DexecutableWar.jetty.sessionIdCookieName=warnings-ng-devenv + - JAVA_OPTS= -Dstapler.jelly.noCache=true -Dhudson.remoting.ClassFilter=com.google.common.collect.ImmutableListMultimap -DexecutableWar.jetty.disableCustomSessionIdCookieName=true -DexecutableWar.jetty.sessionIdCookieName=codingstyle user: ${CURRENT_UID} restart: unless-stopped - java11-agent: - build: ./docker/images/java11-agent depends_on: - - jenkins-controller + key-generator: + condition: service_completed_successfully # Depends on the successful completion of the sidekick_service + healthcheck: + test: ["CMD-SHELL", "[ -f /ssh-dir/conductor_ok ] || exit 1"] + # Checks if the conductor_ok file exists in the /ssh-dir path + interval: 5s + timeout: 10s + retries: 5 + + key-generator: + container_name: key-generator + build: + context: docker/images/key-generator + stdin_open: true + tty: true + # The entrypoint script generates the SSH keys and outputs them to the /ssh-dir directory. + entrypoint: sh -c "/usr/local/bin/keygen.sh /ssh-dir" # Runs the keygen.sh script and specifies the output directory + volumes: + - agent-ssh-dir:/ssh-dir # Mounts the agent-ssh-dir volume to the /ssh-dir path inside the container + # The healthcheck command checks if the conductor_ok file exists in the /ssh-dir directory. + healthcheck: + test: ["CMD-SHELL", "[ -f /ssh-dir/conductor_ok ] || exit 1"] + # Checks if the conductor_ok file exists in the /ssh-dir path + interval: 5s + timeout: 10s + retries: 5 + + java-agent: + container_name: java-agent + build: docker/images/java-agent + depends_on: + key-generator: + condition: service_completed_successfully # Depends on the successful completion of the sidekick_service + jenkins: + condition: service_started restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "[ -f /ssh-dir/conductor_ok ] || exit 1"] + # Checks if the conductor_ok file exists in the /ssh-dir path + interval: 5s + timeout: 10s + retries: 5 + volumes: + - agent-ssh-dir:/home/jenkins/.ssh:ro # Mounts the agent-ssh-dir volume to the /home/jenkins/.ssh path inside the container as read-only + - ${HOME}/.m2/repository:/home/jenkins/.m2/repository # Mounts the local Maven repository to the /home/jenkins/.m2 path inside the container + +volumes: + agent-ssh-dir: + name: agent-ssh-dir # Creates a named volume called agent-ssh-dir + jenkins_home: + name: jenkins_home # Creates a named volume called jenkins_home + external: true diff --git a/docker/images/java-agent/Dockerfile b/docker/images/java-agent/Dockerfile new file mode 100644 index 00000000..2bb4ad6f --- /dev/null +++ b/docker/images/java-agent/Dockerfile @@ -0,0 +1,27 @@ +FROM jenkins/ssh-agent:latest-jdk21 + +# Install prerequisites for Java and Maven +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates curl \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Install Maven +ARG MAVEN_VERSION=3.9.8 + +SHELL ["/bin/bash", "-eo", "pipefail", "-c"] +RUN curl -sS -L -O --output-dir /tmp/ --create-dirs https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz \ + && printf "%s" "$(sha512sum /tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz)" | sha512sum -c - \ + && curl -sS -L -O --output-dir /tmp/ --create-dirs https://downloads.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz.sha512 \ + && printf "%s /tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz" "$(cat /tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz.sha512)" | sha512sum --check --status - \ + && tar xzf "/tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz" -C /opt/ \ + && rm "/tmp/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \ + && ln -s /opt/apache-maven-${MAVEN_VERSION} /opt/maven \ + && ln -s /opt/maven/bin/mvn /usr/bin/mvn \ + && mkdir -p /etc/profile.d \ + && echo "export JAVA_HOME=$JAVA_HOME \n \ + export M2_HOME=/opt/maven \n \ + export PATH=${M2_HOME}/bin:${PATH}" > /etc/profile.d/maven.sh +ENV M2_HOME="/opt/maven" +ENV PATH="${M2_HOME}/bin/:${PATH}" +RUN echo "PATH=${PATH}" >> /etc/environment && chown -R jenkins:jenkins "${JENKINS_AGENT_HOME}" diff --git a/docker/images/java11-agent/Dockerfile b/docker/images/java11-agent/Dockerfile deleted file mode 100644 index 871fcbbb..00000000 --- a/docker/images/java11-agent/Dockerfile +++ /dev/null @@ -1,65 +0,0 @@ -FROM eclipse-temurin:11-alpine - -RUN apk update \ - && apk add bash git openssh dos2unix curl \ - && mkdir /root/.ssh \ - && chmod 0700 /root/.ssh \ - && ssh-keygen -A \ - && sed -i s/^#PasswordAuthentication\ yes/PasswordAuthentication\ no/ /etc/ssh/sshd_config \ - && sed -i -e "s/MACs /MACs hmac-sha1,/g" /etc/ssh/sshd_config \ - && echo "RSAAuthentication yes" > /etc/ssh/sshd_config \ - && echo "UsePAM yes" > /etc/ssh/sshd_config \ - && echo "PubkeyAuthentication yes" > /etc/ssh/sshd_config -USER root - -ARG MAVEN_VERSION=3.8.6 -ARG USER_HOME_DIR="/root" -ARG SHA=f790857f3b1f90ae8d16281f902c689e4f136ebe584aba45e4b1fa66c80cba826d3e0e52fdd04ed44b4c66f6d3fe3584a057c26dfcac544a60b301e6d0f91c26 -ARG BASE_URL=https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries - -RUN mkdir -p /opt/maven /opt/maven/ref \ - && echo "Downloading maven" \ - && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \ - \ - && echo "Checking download hash" \ - && echo "${SHA} /tmp/apache-maven.tar.gz" | sha512sum -c - \ - \ - && echo "Unzipping maven" \ - && tar -xzf /tmp/apache-maven.tar.gz -C /opt/maven --strip-components=1 \ - \ - && echo "Cleaning and setting links" \ - && rm -f /tmp/apache-maven.tar.gz \ - && ln -s /opt/maven/bin/mvn /usr/bin/mvn - -RUN addgroup -S jenkins && adduser -D agent -G jenkins -RUN echo "agent:Docker!" | chpasswd - -RUN mkdir /home/agent/.ssh -RUN chmod 700 /home/agent/.ssh -RUN chown agent:jenkins /home/agent/.ssh - -COPY --chown=agent:jenkins unsafe.pub /home/agent/.ssh/authorized_keys -RUN chmod 600 /home/agent/.ssh/authorized_keys - -RUN mkdir /var/data -VOLUME /var/data - -COPY docker-entrypoint.sh / -RUN chmod u+x docker-entrypoint.sh -RUN dos2unix /docker-entrypoint.sh - -RUN git config --global user.name "Jenkins Java 11 Agent" -RUN git config --global user.email "java11.agent@jenkins.master" - -EXPOSE 22 - -ENV JAVA_HOME /opt/java/openjdk -ENV MAVEN_HOME /opt/maven - -RUN java --version -RUN mvn --version - -ENTRYPOINT ["/docker-entrypoint.sh"] - -# -D in CMD below prevents sshd from becoming a daemon. -e is to log everything to stderr. -CMD ["/usr/sbin/sshd", "-D", "-e"] diff --git a/docker/images/java11-agent/docker-entrypoint.sh b/docker/images/java11-agent/docker-entrypoint.sh deleted file mode 100644 index c9185eee..00000000 --- a/docker/images/java11-agent/docker-entrypoint.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -if [ ! -f "/etc/ssh/ssh_host_rsa_key" ]; then - # generate fresh rsa key - ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa -fi -if [ ! -f "/etc/ssh/ssh_host_dsa_key" ]; then - # generate fresh dsa key - ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa -fi - -# prepare run dir -if [ ! -d "/var/run/sshd" ]; then - mkdir -p /var/run/sshd -fi - -TARGET_GID=$(stat -c "%g" /var/data) -addgroup -g $TARGET_GID tempgroup -addgroup agent tempgroup -chmod 770 /var/data -chmod g+s /var/data -chown agent:jenkins /var/data - -echo Added user agent to group GID $TARGET_GID - -# Execute the CMD from the Dockerfile: -exec "$@" diff --git a/docker/images/java11-agent/unsafe b/docker/images/java11-agent/unsafe deleted file mode 100644 index d7d7b319..00000000 --- a/docker/images/java11-agent/unsafe +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA86cZk1vZh/OwzJDEqga0nnKEh1QpCm1uSDjvuLp2pPDPHMp/ -m9Il9O8ZAZ+IVCUXygO3s1BvBF/a7uVYp7XqjDiTj5Jwrs5lEtl4/1iXXKtwbpAc -bsoiEaFDl7Amc4pUfwzsjaqY4yN4jW+JaLOf/+GqCjwpiyJxZ0N2ONlWoph9dvfH -JBK+LUcbKIqbBAADT12d6ePIBsDn9Yaeem0xSJrwEzcMTFYj6asinMlWgO7VwgZx -JPxhMG+jIq6Mh20tFbwc/XGTqSb/vMkJ8i53RnYm5PoT2xqeYlQCLJtvBRBfuBb5 -WJaQcKvTmLoTgkRCbx/QsQzIWzl4MCj56PRsjQIDAQABAoIBAAGTiy7Q4U9n3DT2 -ms8ey/xacVEO0lUm8Be3hpWDX1Eh3bUp+jlf2q8C/P5tscwZkVXVQFMAqjc1B42U -Hka3fpT5qLq9D82RuEWu8oF0aUZINaoBdK2i0SWcDXvlv9nvgyxvQPiJqgOOLzF7 -D0CGKPrW0urOCNbFmkY4wYMMpOrYXnwb6bc1p7snbzeRigaoGvSgvH7fx2Steg1o -j50C4BKVtXPKQdmckG2SFn0T+U1iCsRG+KNcENX2vX8gyrXImAH093WTjKsmM9et -ddWB+molSnXR/MNrf6BB2mpvXLNyR2/RgBd2jwSQnpDkpms4Br5nek3YYN1dBRL4 -6bofHWECgYEA+7n5OIEbvpMtGxJwOovj0KZMzPkHyQH/DZzo48rS+39goNk/0KLF -c3L3sHbT3Lr4qA/6JOCjlzw7o2AbOrRL4ke1uqcCVQMdDqZdvNezMvTzqEbQGdHD -aFnEcUV2tvEwP11q37ianBRPH5stOnEwQNuv6AJo5LKwi4mTS7qEW9cCgYEA98oJ -h+vMKpXGdJzkSDMzYBrC2tYgqjby6+zGKz8BZ58YecsL+oi2GXBaDTfK+16CKeFM -8+qQN9Kl1ZNOlk64XJXjt77h0FcFuGe+6rUpM1aEizrf9sWPVZO+QQfhnjsiAhtQ -YX783ydy9rMn1FDPMtNNq4GMhGsFCaL4RupOjjsCgYAnk9XbTHFQRVOSLhP3IIdx -BrSMhZrzv5yaR1FWf00svZozr/SYmP7yZ+EJnaUxzzPJOLnbknYmERJPXYzqbe6A -ZUXtUtTLCPJIm1+hkUhbeqfUjU2qwZA3l+WK6aEAomszizyCcEPexlKqZXt29NTh -XakKkVZsnqujRL4j6e9lgQKBgQDvhD8EQJyAyXgkvoc3dy6BBj019WdrwWO9Q4km -wmdkN3gcOnYgvUdwfZa+UiEGLAub2eldmW3AWADu2s5LIlq5PDX7Jir3DTc9UiNM -ksL5mfbS8p0M11i+uupbx/eB0N0FtktTgsGCH4rUBsdIRriSA4h/cOFYGm6rKvnc -6p32gwKBgHZYmXzuBWZlWEmPiXbTaI4egJugur5FrT6BJfiLsN2MHBJi9k1IpKEP -SaT+v0IXJ8jP4gSiu4/gyJQpkn7yiMNhwYWlQt+1zyIkHjUsEG82Z8Mqpjx2EJgG -MxDybQux1uk0hyCmMS757WkbTyi0pTWz7PgTIdfmYqhZVV8KRSUi ------END RSA PRIVATE KEY----- diff --git a/docker/images/java11-agent/unsafe.pub b/docker/images/java11-agent/unsafe.pub deleted file mode 100644 index 0305a8c3..00000000 --- a/docker/images/java11-agent/unsafe.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzpxmTW9mH87DMkMSqBrSecoSHVCkKbW5IOO+4unak8M8cyn+b0iX07xkBn4hUJRfKA7ezUG8EX9ru5VinteqMOJOPknCuzmUS2Xj/WJdcq3BukBxuyiIRoUOXsCZzilR/DOyNqpjjI3iNb4los5//4aoKPCmLInFnQ3Y42VaimH1298ckEr4tRxsoipsEAANPXZ3p48gGwOf1hp56bTFImvATNwxMViPpqyKcyVaA7tXCBnEk/GEwb6MiroyHbS0VvBz9cZOpJv+8yQnyLndGdibk+hPbGp5iVAIsm28FEF+4FvlYlpBwq9OYuhOCREJvH9CxDMhbOXgwKPno9GyN unsafe@nowhere diff --git a/docker/images/jenkins-controller/Dockerfile b/docker/images/jenkins-controller/Dockerfile index 96dcae18..7b8d42ae 100644 --- a/docker/images/jenkins-controller/Dockerfile +++ b/docker/images/jenkins-controller/Dockerfile @@ -1,17 +1,28 @@ -FROM jenkins/jenkins:lts-alpine +# Prepare a Debian-based Docker image with several utilities installed to automatically generate SSH keys +FROM jenkins/jenkins:latest-jdk21 -USER root -RUN addgroup -g 102 docker -RUN adduser jenkins docker -RUN apk add libltdl +# We switch back to the Jenkins user for the remaining operations. USER jenkins -# Install plugins +# We copy the jobs directory from our current directory to the Jenkins home directory in the image. +COPY preconfigured-jobs /usr/share/jenkins/ref/jobs + +# We write the Jenkins version to the UpgradeWizard state file. +# This prevents the Upgrade Wizard from showing up when Jenkins starts. +RUN echo "${JENKINS_VERSION}" > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state + +# We copy a list of plugins to install to the Jenkins ref directory in the image. COPY plugins.txt /usr/share/jenkins/ref/plugins.txt + +# We use the Jenkins plugin CLI to install the plugins listed in the plugins.txt file. RUN jenkins-plugin-cli --verbose -f /usr/share/jenkins/ref/plugins.txt -# Create admin user and don't start the wizard -RUN echo 2.0 > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state +# We copy a pre-configured Jenkins configuration file to the Jenkins ref directory in the image. +# This allows us to pre-configure Jenkins with our desired settings. +COPY jenkins.yaml /usr/share/jenkins/ref/jenkins.yaml + +# Create an admin user and don't start the wizard +RUN echo 2.x > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state ENV JENKINS_OPTS -Djenkins.install.runSetupWizard=false COPY security.groovy /usr/share/jenkins/ref/init.groovy.d/basic-security.groovy diff --git a/docker/images/jenkins-controller/jenkins.yaml b/docker/images/jenkins-controller/jenkins.yaml index 3a48a123..3a4792b0 100644 --- a/docker/images/jenkins-controller/jenkins.yaml +++ b/docker/images/jenkins-controller/jenkins.yaml @@ -7,6 +7,8 @@ jenkins: standard: excludeClientIPFromCrumb: false disableRememberMe: false + disabledAdministrativeMonitors: + - "hudson.diagnosis.ReverseProxySetupMonitor" markupFormatter: rawHtml: disableSyntaxHighlighting: false @@ -14,48 +16,106 @@ jenkins: myViewsTabBar: "standard" nodes: - permanent: + labelString: "docker linux agent java jdk21 java21" launcher: ssh: - credentialsId: "java-agent-ssh-private-key" - host: "java11-agent" - launchTimeoutSeconds: 210 - maxNumRetries: 10 + credentialsId: "jenkins-ssh-agent-private-key" + host: "java-agent" port: 22 - retryWaitTime: 15 - jvmOptions: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8001" - javaPath: "/opt/java/openjdk/bin/java" sshHostKeyVerificationStrategy: "nonVerifyingKeyVerificationStrategy" - name: "java11-agent" + jvmOptions: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8001" + name: "java-agent" + nodeDescription: "Jenkins Docker Agent with Java 21 and Maven" numExecutors: 1 - remoteFS: "/var/data" - nodeProperties: - - envVars: - env: - - key: "JAVA_HOME" - value: "/opt/java/openjdk" - - key: "MAVEN_HOME" - value: "/opt/maven" + remoteFS: "/home/jenkins/agent" + retentionStrategy: "always" numExecutors: 0 primaryView: - all: - name: "all" + list: + columns: + - "status" + - "weather" + - "jobName" + - "gitBranchSpecifierColumn" + - "lastSuccess" + - "lastFailure" + - "lastDuration" + - coverageTotalsColumn: + columnName: "Line Coverage" + metric: LINE + - coverageTotalsColumn: + columnName: "Branch Coverage" + metric: BRANCH + - "buildButton" + includeRegex: ".*" + name: "List View" projectNamingStrategy: "standard" quietPeriod: 5 - remotingSecurity: - enabled: true scmCheckoutRetryCount: 0 securityRealm: local: allowsSignup: false enableCaptcha: false slaveAgentPort: 50000 - systemMessage: "