diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec91544 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +volumes/*/ \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 38bacaf..0c4c7be 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,78 +1,136 @@ version: '3.7' services: - jenkins: - build: ./jenkins - container_name: jenkins - user: root - volumes: - - jenkins-log:/var/log/jenkins - - jenkins-data:/var/jenkins_home - - ./jenkins/downloads:/var/jenkins_home/downloads - - /var/run/docker.sock:/var/run/docker.sock - secrets: - - jenkins_admin_username - - jenkins_admin_password + # Nginx reverse proxy container + # Reference: + # https://github.com/jwilder/nginx-proxy + nginx-proxy: # TODO: maybe split this to the two underlying images? + image: jwilder/nginx-proxy + container_name: nginx-proxy + restart: always environment: - - VIRTUAL_HOST=jenkins.mthmmy.tk - - VIRTUAL_PORT=8080 - - LETSENCRYPT_HOST=jenkins.mthmmy.tk - - LETSENCRYPT_EMAIL=apotwohd@gmail.com - - SONARQUBE_HOST=127.0.0.1:9000 + - DEFAULT_HOST=mthmmy.tk + labels: + com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true" + logging: + options: + max-size: '4m' + max-file: '10' networks: - janus-net - nginx-proxy: - image: jwilder/nginx-proxy - container_name: nginx-proxy ports: - "80:80" - "443:443" - networks: - - janus-net volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - - DEFAULT_HOST=mthmmy.tk - - conf:/etc/nginx/conf.d - - vhost:/etc/nginx/vhost.d - - html:/usr/share/nginx/html - - dhparam:/etc/nginx/dhparam - - certs:/etc/nginx/certs:ro + - ./volumes/nginx/conf:/etc/nginx/conf.d + - ./volumes/nginx/vhost:/etc/nginx/vhost.d + - ./volumes/nginx/html:/usr/share/nginx/html + - ./volumes/nginx/dhparam:/etc/nginx/dhparam + - ./volumes/nginx/certs:/etc/nginx/certs:ro + + # Letsencrypt automated creation, renewal and use of Let's Encrypt certificates + # Reference: + # https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion container_name: nginx-proxy-le + restart: always + depends_on: + - nginx-proxy + logging: + options: + max-size: '4m' + max-file: '10' + networks: + - janus-net volumes: - - conf:/etc/nginx/conf.d - - vhost:/etc/nginx/vhost.d - - html:/usr/share/nginx/html - - dhparam:/etc/nginx/dhparam - - certs:/etc/nginx/certs:rw + - ./volumes/nginx/conf:/etc/nginx/conf.d + - ./volumes/nginx/vhost:/etc/nginx/vhost.d + - ./volumes/nginx/html:/usr/share/nginx/html + - ./volumes/nginx/dhparam:/etc/nginx/dhparam + - ./volumes/nginx/certs:/etc/nginx/certs:rw - /var/run/docker.sock:/var/run/docker.sock:ro + + # Jenkins automation server, image bundled with Blue Ocean + # Reference: + # https://jenkins.io/doc/book/blueocean/ + jenkins: + build: ./jenkins + container_name: jenkins + restart: always + user: root environment: - - NGINX_PROXY_CONTAINER=nginx-proxy + - VIRTUAL_HOST=jenkins.mthmmy.tk + - VIRTUAL_PORT=8080 + - LETSENCRYPT_HOST=jenkins.mthmmy.tk + - LETSENCRYPT_EMAIL=apotwohd@gmail.com + - SONARQUBE_HOST=127.0.0.1:9000 + secrets: + - jenkins_admin_username + - jenkins_admin_password networks: - janus-net + volumes: + - ./volumes/jenkins/log:/var/log/jenkins + - jenkins-data:/var/jenkins_home + - ./jenkins/downloads:/var/jenkins_home/downloads + - /var/run/docker.sock:/var/run/docker.sock + + # Sonarqube continuous inspection of code quality + # References: + # https://docs.sonarqube.org/latest/ + # https://github.com/SonarSource/docker-sonarqube/tree/master/recipes sonarqube: image: sonarqube container_name: sonarqube - ports: - - "9000:9000" + restart: always + environment: + - sonar.jdbc.username=sonar + - sonar.jdbc.password=sonar + - sonar.jdbc.url=jdbc:postgresql://sonar-db:5432/sonar + - VIRTUAL_HOST=sonar.mthmmy.tk + - VIRTUAL_PORT=9000 + - LETSENCRYPT_HOST=sonar.mthmmy.tk + - LETSENCRYPT_EMAIL=apotwohd@gmail.com networks: - janus-net - expose: - - "9000" -secrets: + - sonar-net + volumes: + - sonarqube_conf:/opt/sonarqube/conf + - sonarqube_data:/opt/sonarqube/data + - sonarqube_extensions:/opt/sonarqube/extensions + - sonarqube_bundled-plugins:/opt/sonarqube/lib/bundled-plugins + sonar-db: + image: postgres + container_name: sonar-db + restart: always + environment: # TODO: figure out another way to pass the username and password + - POSTGRES_USER=sonar + - POSTGRES_PASSWORD=sonar + volumes: + - postgresql:/var/lib/postgresql + - postgresql_data:/var/lib/postgresql/data + networks: + - sonar-net + +# Networks in use +# TODO: maybe add/split to separate networks +networks: + janus-net: + driver: bridge + sonar-net: + driver: bridge +# Secrets in use +secrets: # TODO: figure out a better way to do this jenkins_admin_username: file: ./jenkins/user jenkins_admin_password: file: ./jenkins/pass volumes: jenkins-data: - jenkins-log: - conf: - vhost: - html: - dhparam: - certs: -networks: - janus-net: - driver: bridge \ No newline at end of file + sonarqube_conf: + sonarqube_data: + sonarqube_extensions: + sonarqube_bundled-plugins: + postgresql: + postgresql_data: \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..6464e2b --- /dev/null +++ b/install.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# This script will: +# - install docker +# - make temporary changes to your system (vm.max_map_count, fs.file-max and other) + +# ATENTION: run this script as root (use sudo if needed)! + +# Checks for root privileges +if [ "$EUID" -ne 0 ] + then echo "Please run as root." + exit 1 +fi + +# Checks if ports 80 and 443 are in use +SHOULD_EXIT=0 +if [[ `lsof -i -P -n | grep LISTEN | grep '*:80 (LISTEN)'` ]]; then + PORT80USER=`lsof -i -P -n | grep LISTEN | grep '*:80 (LISTEN)' | awk '{ print $1 }'` + echo "Port 80 is in use by another program ($PORT80USER). Please free the port and try again." + SHOULD_EXIT=1 +fi + +if [[ `lsof -i -P -n | grep LISTEN | grep '*:443 (LISTEN)'` ]]; then + PORT443USER=`lsof -i -P -n | grep LISTEN | grep '*:443 (LISTEN)' | awk '{ print $1 }'` + echo "Port 443 is in use by another program ($PORT80USER). Please free the port and try again." + SHOULD_EXIT=1 +fi + +if [[ "$SHOULD_EXIT" = "1" ]]; then + echo "Exiting..." + exit 1 +fi + +# Installs docker using the get.docker.com method +VERSION="18.09" +curl -fsSL https://get.docker.com -o get-docker.sh | sh + +# Bellow settings are needed for Sonarqube to run on linux. +# These settings are valid only for the session and are lost after reboot +# TODO: make the changes permanent +sysctl -w vm.max_map_count=262144 +sysctl -w fs.file-max=65536 +ulimit -n 65536 +ulimit -u 4096 diff --git a/jenkins/Dockerfile b/jenkins/Dockerfile index d8fea6b..3bf388a 100644 --- a/jenkins/Dockerfile +++ b/jenkins/Dockerfile @@ -8,16 +8,15 @@ RUN mkdir /var/cache/jenkins RUN chown -R jenkins:jenkins /var/log/jenkins RUN chown -R jenkins:jenkins /var/cache/jenkins -# Normally we should install docker inside container, but it seems to be working -# without it. +# Installs docker inside container # ATENTION: version MUST be the same as host's docker installation! ARG VERSION=18.09 RUN curl -fsSL https://get.docker.com -o get-docker.sh | sh USER jenkins -# Security configuration script -COPY security.groovy /var/jenkins_home/init.groovy.d/security.groovy +# Security configuration scripts +COPY configuration/* /var/jenkins_home/init.groovy.d/security.groovy # Automatically installs plugins COPY plugins.txt /usr/share/jenkins/ref/plugins.txt @@ -29,5 +28,4 @@ COPY groovy/* /usr/share/jenkins/ref/init.groovy.d/ # Sets defaults # Gets rid of admin password setup ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false -Xmx8192m" - ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" diff --git a/jenkins/configuration/github.groovy b/jenkins/configuration/github.groovy new file mode 100644 index 0000000..f67a27f --- /dev/null +++ b/jenkins/configuration/github.groovy @@ -0,0 +1,37 @@ +import jenkins.model.* +import com.cloudbees.plugins.credentials.* +import com.cloudbees.plugins.credentials.common.* +import com.cloudbees.plugins.credentials.domains.* +import com.cloudbees.plugins.credentials.impl.* +import com.cloudbees.jenkins.plugins.sshcredentials.impl.* +import org.jenkinsci.plugins.plaincredentials.* +import org.jenkinsci.plugins.plaincredentials.impl.* +import hudson.util.Secret +import hudson.plugins.sshslaves.* +import org.apache.commons.fileupload.* +import org.apache.commons.fileupload.disk.* +import java.nio.file.Files + +def env = System.getenv() + +GITHUB_TOKEN = env['GITHUB_TOKEN'] + +domain = Domain.global() +store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore() + +println("== multibranch-github-pipeline.groovy => Starting.") +if ( GITHUB_TOKEN ) { + println("== multibranch-github-pipeline.groovy => Adding token.") + secretText = new StringCredentialsImpl( + CredentialsScope.GLOBAL, + "github-token", + "This is the token used for Github source branch plugin", + Secret.fromString(GITHUB_TOKEN) + ) + + store.addCredentials(domain, secretText) + println("== multibranch-github-pipeline.groovy => token added.") + +} + +println("== multibranch-github-pipeline.groovy => Done.") \ No newline at end of file diff --git a/jenkins/security.groovy b/jenkins/configuration/security.groovy similarity index 100% rename from jenkins/security.groovy rename to jenkins/configuration/security.groovy diff --git a/jenkins/configuration/url.groovy b/jenkins/configuration/url.groovy new file mode 100644 index 0000000..25e823c --- /dev/null +++ b/jenkins/configuration/url.groovy @@ -0,0 +1,13 @@ +import jenkins.model.Jenkins + +def env = System.getenv() + +JENKINS_URL = env['JENKINS_URL'] + +if (JENKINS_URL) { + def location = Jenkins.instance.getDescriptor('jenkins.model.JenkinsLocationConfiguration') + location.setUrl(JENKINS_URL) + println("== 00_jenkins-init.groovy - Jenkins URL configured to " + Jenkins.instance.getRootUrl()) +} else { + println("== 00_jenkins-init.groovy - Jenkins URL not configured. " + Jenkins.instance.getRootUrl()) +} \ No newline at end of file diff --git a/jenkins/plugins.txt b/jenkins/plugins.txt index 1806552..48bbc8a 100644 --- a/jenkins/plugins.txt +++ b/jenkins/plugins.txt @@ -1,105 +1,106 @@ -mailer -blueocean-pipeline-editor -blueocean-i18n -pipeline-model-declarative-agent -github-branch-source -workflow-support -durable-task -cloudbees-folder -workflow-cps-global-lib -token-macro -scm-api -jquery-detached -cloudbees-bitbucket-branch-source -pipeline-stage-tags-metadata -git-server -blueocean-dashboard -git -jdk-tool -pipeline-model-extensions -docker-commons -authentication-tokens -matrix-project -pipeline-github-lib -git-client -email-ext -blueocean -display-url-api -workflow-cps -blueocean-jwt -workflow-durable-task-step -ace-editor -lockable-resources -credentials-binding -blueocean-web -timestamper -plain-credentials -blueocean-commons -blueocean-autofavorite -blueocean-events -gradle -workflow-scm-step -credentials -handy-uri-templates-2-api -blueocean-pipeline-api-impl -discord-notifier -antisamy-markup-formatter -pipeline-rest-api -junit -workflow-basic-steps -pipeline-model-api -github-api -jira -pam-auth -apache-httpcomponents-client-4-api -blueocean-github-pipeline -pipeline-stage-step -ssh-slaves -branch-api -workflow-aggregator -blueocean-config -workflow-step-api -pubsub-light -blueocean-rest -script-security -blueocean-bitbucket-pipeline -blueocean-pipeline-scm-api -blueocean-git-pipeline -bouncycastle-api -momentjs -pipeline-input-step -workflow-multibranch -variant -structs -blueocean-rest-impl -subversion -mapdb-api -pipeline-stage-view -matrix-auth -workflow-job -mercurial -ssh-credentials -sse-gateway -pipeline-graph-analysis -ws-cleanup -jenkins-design-language -pipeline-model-definition -ant -handlebars -command-launcher -ldap -blueocean-personalization -resource-disposer -build-timeout -blueocean-display-url -pipeline-build-step -pipeline-milestone-step -workflow-api -favorite -jackson2-api -blueocean-core-js -docker-workflow -blueocean-jira -htmlpublisher -jsch -github +ace-editor +ant +antisamy-markup-formatter +apache-httpcomponents-client-4-api +authentication-tokens +blueocean +blueocean-autofavorite +blueocean-bitbucket-pipeline +blueocean-commons +blueocean-config +blueocean-core-js +blueocean-dashboard +blueocean-display-url +blueocean-events +blueocean-git-pipeline +blueocean-github-pipeline +blueocean-i18n +blueocean-jira +blueocean-jwt +blueocean-personalization +blueocean-pipeline-api-impl +blueocean-pipeline-editor +blueocean-pipeline-scm-api +blueocean-rest +blueocean-rest-impl +blueocean-web +bouncycastle-api +branch-api +build-timeout +cloudbees-bitbucket-branch-source +cloudbees-folder +command-launcher +credentials +credentials-binding +discord-notifier +display-url-api +docker-commons +docker-workflow +durable-task +email-ext +favorite +git +git-client +git-server +github +github-api +github-branch-source +gradle +handlebars +handy-uri-templates-2-api +htmlpublisher +jackson2-api +jdk-tool +jenkins-design-language +jira +jquery-detached +jsch +junit +ldap +lockable-resources +mailer +mapdb-api +matrix-auth +matrix-project +mercurial +momentjs +pam-auth +pipeline-build-step +pipeline-github-lib +pipeline-graph-analysis +pipeline-input-step +pipeline-milestone-step +pipeline-model-api +pipeline-model-declarative-agent +pipeline-model-definition +pipeline-model-extensions +pipeline-rest-api +pipeline-stage-step +pipeline-stage-tags-metadata +pipeline-stage-view +plain-credentials +pubsub-light +resource-disposer +scm-api +script-security +sonar +sse-gateway +ssh-credentials +ssh-slaves +structs +subversion +timestamper +token-macro +variant +workflow-aggregator +workflow-api +workflow-basic-steps +workflow-cps +workflow-cps-global-lib +workflow-durable-task-step +workflow-job +workflow-multibranch +workflow-scm-step +workflow-step-api +workflow-support +ws-cleanup diff --git a/utility-scripts/updateJenkinsPlugins.sh b/utility-scripts/updateJenkinsPlugins.sh new file mode 100755 index 0000000..14a0a39 --- /dev/null +++ b/utility-scripts/updateJenkinsPlugins.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +docker exec -it jenkins ls /var/jenkins_home/plugins/ | grep -v jpi > "$DIR/../jenkins/plugins.txt" \ No newline at end of file diff --git a/volumes/.gitkeep b/volumes/.gitkeep new file mode 100644 index 0000000..e69de29