wanghongkai 6 years ago
commit
776ec43eb5

+ 17 - 0
Dockerfile

@@ -0,0 +1,17 @@
+FROM jenkins/jenkins
+
+# 镜像加速
+ENV JENKINS_UC http://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
+ENV JENKINS_UC_DOWNLOAD http://mirrors.tuna.tsinghua.edu.cn/jenkins
+# 跳过setup
+ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false
+
+# 需求插件
+COPY plugins.txt /usr/share/jenkins/plugins.txt
+COPY plugins.sh /usr/local/bin/install-plugins.sh
+RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/plugins.txt
+
+# configure script
+COPY config/*.groovy /usr/share/jenkins/ref/init.groovy.d/
+
+USER root

+ 7 - 0
README.md

@@ -0,0 +1,7 @@
+Docker build镜像后修改docker-compose中的对应service使用镜像达到快速部署
+
+生产的API TOKEN 同config.json中jenkins用户的token
+
+在挂载的jenkins_home对应目录下有MOOCODER_JENKINS存放API TOKEN 遗失可以去这里找回
+
+config中的groovy按字典顺序执行,有额外需要可以进行调整与补充

+ 1 - 0
config.json

@@ -0,0 +1 @@
+{"jenkins": {"username": "admin", "password": "NJU67jenkins"}, "num_executors": 4, "gitlab": {"username": "root", "password": "NJU67gitlab"}, "jenkins_url": "http://172.19.240.15:8081", "global_env": [{"MOOCODER_HOST": "172.19.240.15:8080"}, {"MOOCODER_SECRET": "1qaz2wsx"}]}

+ 19 - 0
config/create-api-token.groovy

@@ -0,0 +1,19 @@
+#!groovy
+import groovy.json.JsonSlurper
+import hudson.model.*
+import jenkins.model.*
+import jenkins.security.*
+import jenkins.security.apitoken.*
+
+def parser = new JsonSlurper()
+def config = parser.parseText(new File('/var/jenkins_home/config.json').text)
+
+def u = User.get(config.jenkins.username)
+def t = u.getProperty(ApiTokenProperty.class)
+def token = t.tokenStore.generateNewToken("JENKINS_TOKEN")
+u.save()
+new File('/var/jenkins_home/JENKINS_TOKEN').withWriter('utf-8') {
+  writer -> writer.write token.plainValue
+}
+println "token is $token.plainValue"
+

+ 27 - 0
config/credentials.groovy

@@ -0,0 +1,27 @@
+#!groovy
+
+import groovy.json.JsonSlurper
+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 hudson.plugins.sshslaves.*;
+
+def domain = Domain.global()
+def store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
+
+def parser = new JsonSlurper()
+def config = parser.parseText(new File('/var/jenkins_home/config.json').text)
+
+gitlabCredentials = new UsernamePasswordCredentialsImpl(
+  CredentialsScope.GLOBAL,
+  "Gitlab", "Gitlab Credentials",
+  config.gitlab.username,
+  config.gitlab.password
+)
+
+println "--> creating credentials"
+
+store.addCredentials(domain, gitlabCredentials)

+ 23 - 0
config/security.groovy

@@ -0,0 +1,23 @@
+#!groovy
+
+import groovy.json.JsonSlurper
+import jenkins.model.*
+import hudson.security.*
+import jenkins.security.s2m.AdminWhitelistRule
+
+def instance = Jenkins.getInstance()
+
+def parser = new JsonSlurper()
+def config = parser.parseText(new File('/var/jenkins_home/config.json').text)
+
+def hudsonRealm = new HudsonPrivateSecurityRealm(false)
+hudsonRealm.createAccount(config.jenkins.username, config.jenkins.password)
+instance.setSecurityRealm(hudsonRealm)
+
+def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
+instance.setAuthorizationStrategy(strategy)
+instance.save()
+
+println "--> creating admin user"
+
+Jenkins.instance.getInjector().getInstance(AdminWhitelistRule.class).setMasterKillSwitch(false)

+ 11 - 0
config/set-executors.groovy

@@ -0,0 +1,11 @@
+#!groovy
+import groovy.json.JsonSlurper
+import jenkins.model.*
+import hudson.model.*
+
+def parser = new JsonSlurper()
+def config = parser.parseText(new File('/var/jenkins_home/config.json').text)
+
+Jenkins.instance.setNumExecutors(config.num_executors)
+println "--> set executors"
+

+ 32 - 0
config/set-global-environment.groovy

@@ -0,0 +1,32 @@
+#!groovy
+import groovy.json.JsonSlurper
+import jenkins.model.*
+import hudson.security.*
+import hudson.model.*
+import hudson.slaves.*
+
+def instance = Jenkins.getInstance()
+
+def parser = new JsonSlurper()
+def config = parser.parseText(new File('/var/jenkins_home/config.json').text)
+
+globalNodeProperties  = instance.getGlobalNodeProperties()
+envVarsNodePropertyList = globalNodeProperties.getAll(EnvironmentVariablesNodeProperty.class)
+newEnvVarsNodeProperty = null
+envVars = null
+
+if ( envVarsNodePropertyList == null || envVarsNodePropertyList.size() == 0 ) {
+  newEnvVarsNodeProperty = new EnvironmentVariablesNodeProperty();
+  globalNodeProperties.add(newEnvVarsNodeProperty)
+  envVars = newEnvVarsNodeProperty.getEnvVars()
+} else {
+  envVars = envVarsNodePropertyList.get(0).getEnvVars()
+}
+
+for (prop in config.global_env) {
+  envVars.put(prop.keySet()[0], prop[prop.keySet()[0]])
+}
+
+println "--> adding global envs"
+
+instance.save()

+ 12 - 0
config/set-jenkins-url.groovy

@@ -0,0 +1,12 @@
+#!groovy
+import groovy.json.JsonSlurper
+import jenkins.model.*
+import hudson.model.*
+
+def parser = new JsonSlurper()
+def config = parser.parseText(new File('/var/jenkins_home/config.json').text)
+JenkinsLocationConfiguration location = Jenkins.instance.getExtensionList('jenkins.model.JenkinsLocationConfiguration')[0]
+
+location.url = config.jenkins_url
+println "--> set jenkins url"
+location.save()

+ 289 - 0
plugin.sh

@@ -0,0 +1,289 @@
+#!/bin/bash -eu
+
+# Resolve dependencies and download plugins given on the command line
+#
+# FROM jenkins
+# RUN install-plugins.sh docker-slaves github-branch-source
+#
+# Environment variables:
+# REF: directory with preinstalled plugins. Default: /usr/share/jenkins/ref/plugins
+# JENKINS_WAR: full path to the jenkins.war. Default: /usr/share/jenkins/jenkins.war
+# JENKINS_UC: url of the Update Center. Default: ""
+# JENKINS_UC_EXPERIMENTAL: url of the Experimental Update Center for experimental versions of plugins. Default: ""
+# JENKINS_INCREMENTALS_REPO_MIRROR: url of the incrementals repo mirror. Default: ""
+# JENKINS_UC_DOWNLOAD: download url of the Update Center. Default: JENKINS_UC/download
+# CURL_OPTIONS When downloading the plugins with curl. Curl options. Default: -sSfL
+# CURL_CONNECTION_TIMEOUT When downloading the plugins with curl. <seconds> Maximum time allowed for connection. Default: 20
+# CURL_RETRY When downloading the plugins with curl. Retry request if transient problems occur. Default: 3
+# CURL_RETRY_DELAY When downloading the plugins with curl. <seconds> Wait time between retries. Default: 0
+# CURL_RETRY_MAX_TIME When downloading the plugins with curl. <seconds> Retry only within this period. Default: 60
+
+set -o pipefail
+
+
+JENKINS_WAR=${JENKINS_WAR:-/usr/share/jenkins/jenkins.war}
+
+. /usr/local/bin/jenkins-support
+
+REF_DIR="${REF}/plugins"
+FAILED="$REF_DIR/failed-plugins.txt"
+
+getLockFile() {
+    printf '%s' "$REF_DIR/${1}.lock"
+}
+
+getArchiveFilename() {
+    printf '%s' "$REF_DIR/${1}.jpi"
+}
+
+download() {
+    local plugin originalPlugin version lock ignoreLockFile url
+    plugin="$1"
+    version="${2:-latest}"
+    ignoreLockFile="${3:-}"
+    url="${4:-}"
+    lock="$(getLockFile "$plugin")"
+
+    if [[ $ignoreLockFile ]] || mkdir "$lock" &>/dev/null; then
+        if ! doDownload "$plugin" "$version" "$url"; then
+            # some plugin don't follow the rules about artifact ID
+            # typically: docker-plugin
+            originalPlugin="$plugin"
+            plugin="${plugin}-plugin"
+            if ! doDownload "$plugin" "$version" "$url"; then
+                echo "Failed to download plugin: $originalPlugin or $plugin" >&2
+                echo "Not downloaded: ${originalPlugin}" >> "$FAILED"
+                return 1
+            fi
+        fi
+
+        if ! checkIntegrity "$plugin"; then
+            echo "Downloaded file is not a valid ZIP: $(getArchiveFilename "$plugin")" >&2
+            echo "Download integrity: ${plugin}" >> "$FAILED"
+            return 1
+        fi
+
+        resolveDependencies "$plugin"
+    fi
+}
+
+doDownload() {
+    local plugin version url jpi
+    plugin="$1"
+    version="$2"
+    url="$3"
+    jpi="$(getArchiveFilename "$plugin")"
+
+    # If plugin already exists and is the same version do not download
+    if test -f "$jpi" && unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | grep "^Plugin-Version: ${version}$" > /dev/null; then
+        echo "Using provided plugin: $plugin"
+        return 0
+    fi
+
+    if [[ -n $url ]] ; then
+        echo "Will use url=$url"
+    elif [[ "$version" == "latest" && -n "$JENKINS_UC_LATEST" ]]; then
+        # If version-specific Update Center is available, which is the case for LTS versions,
+        # use it to resolve latest versions.
+        url="$JENKINS_UC_LATEST/latest/${plugin}.hpi"
+    elif [[ "$version" == "experimental" && -n "$JENKINS_UC_EXPERIMENTAL" ]]; then
+        # Download from the experimental update center
+        url="$JENKINS_UC_EXPERIMENTAL/latest/${plugin}.hpi"
+    elif [[ "$version" == incrementals* ]] ; then
+        # Download from Incrementals repo: https://jenkins.io/blog/2018/05/15/incremental-deployment/
+        # Example URL: https://repo.jenkins-ci.org/incrementals/org/jenkins-ci/plugins/workflow/workflow-support/2.19-rc289.d09828a05a74/workflow-support-2.19-rc289.d09828a05a74.hpi
+        local groupId incrementalsVersion
+        # add a trailing ; so the \n gets added to the end
+        readarray -t "-d;" arrIN <<<"${version};";
+        unset 'arrIN[-1]';
+        groupId=${arrIN[1]}
+        incrementalsVersion=${arrIN[2]}
+        url="${JENKINS_INCREMENTALS_REPO_MIRROR}/$(echo "${groupId}" | tr '.' '/')/${plugin}/${incrementalsVersion}/${plugin}-${incrementalsVersion}.hpi"
+    else
+        JENKINS_UC_DOWNLOAD=${JENKINS_UC_DOWNLOAD:-"$JENKINS_UC/download"}
+        url="$JENKINS_UC_DOWNLOAD/plugins/$plugin/$version/${plugin}.hpi"
+    fi
+
+    echo "Downloading plugin: $plugin from $url"
+    # We actually want to allow variable value to be split into multiple options passed to curl.
+    # This is needed to allow long options and any options that take value.
+    # shellcheck disable=SC2086
+    retry_command curl ${CURL_OPTIONS:--sSfL} --connect-timeout "${CURL_CONNECTION_TIMEOUT:-20}" --retry "${CURL_RETRY:-3}" --retry-delay "${CURL_RETRY_DELAY:-0}" --retry-max-time "${CURL_RETRY_MAX_TIME:-60}" "$url" -o "$jpi"
+    return $?
+}
+
+checkIntegrity() {
+    local plugin jpi
+    plugin="$1"
+    jpi="$(getArchiveFilename "$plugin")"
+
+    unzip -t -qq "$jpi" >/dev/null
+    return $?
+}
+
+resolveDependencies() {
+    local plugin jpi dependencies
+    plugin="$1"
+    jpi="$(getArchiveFilename "$plugin")"
+
+    dependencies="$(unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | tr '\n' '|' | sed -e 's#| ##g' | tr '|' '\n' | grep "^Plugin-Dependencies: " | sed -e 's#^Plugin-Dependencies: ##')"
+
+    if [[ ! $dependencies ]]; then
+        echo " > $plugin has no dependencies"
+        return
+    fi
+
+    echo " > $plugin depends on $dependencies"
+
+    IFS=',' read -r -a array <<< "$dependencies"
+
+    for d in "${array[@]}"
+    do
+        plugin="$(cut -d':' -f1 - <<< "$d")"
+        if [[ $d == *"resolution:=optional"* ]]; then
+            echo "Skipping optional dependency $plugin"
+        else
+            local pluginInstalled
+            if pluginInstalled="$(echo -e "${bundledPlugins}\n${installedPlugins}" | grep "^${plugin}:")"; then
+                pluginInstalled="${pluginInstalled//[$'\r']}"
+                local versionInstalled; versionInstalled=$(versionFromPlugin "${pluginInstalled}")
+                local minVersion; minVersion=$(versionFromPlugin "${d}")
+                if versionLT "${versionInstalled}" "${minVersion}"; then
+                    echo "Upgrading bundled dependency $d ($minVersion > $versionInstalled)"
+                    download "$plugin" &
+                else
+                    echo "Skipping already installed dependency $d ($minVersion <= $versionInstalled)"
+                fi
+            else
+                download "$plugin" &
+            fi
+        fi
+    done
+    wait
+}
+
+bundledPlugins() {
+    if [ -f "$JENKINS_WAR" ]
+    then
+        TEMP_PLUGIN_DIR=/tmp/plugintemp.$$
+        for i in $(jar tf "$JENKINS_WAR" | grep -E '[^detached-]plugins.*\..pi' | sort)
+        do
+            rm -fr $TEMP_PLUGIN_DIR
+            mkdir -p $TEMP_PLUGIN_DIR
+            PLUGIN=$(basename "$i"|cut -f1 -d'.')
+            (cd $TEMP_PLUGIN_DIR;jar xf "$JENKINS_WAR" "$i";jar xvf "$TEMP_PLUGIN_DIR/$i" META-INF/MANIFEST.MF >/dev/null 2>&1)
+            VER=$(grep -E -i Plugin-Version "$TEMP_PLUGIN_DIR/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //')
+            echo "$PLUGIN:$VER"
+        done
+        rm -fr $TEMP_PLUGIN_DIR
+    else
+        echo "war not found, installing all plugins: $JENKINS_WAR"
+    fi
+}
+
+versionFromPlugin() {
+    local plugin=$1
+    if [[ $plugin =~ .*:.* ]]; then
+        echo "${plugin##*:}"
+    else
+        echo "latest"
+    fi
+
+}
+
+installedPlugins() {
+    for f in "$REF_DIR"/*.jpi; do
+        echo "$(basename "$f" | sed -e 's/\.jpi//'):$(get_plugin_version "$f")"
+    done
+}
+
+jenkinsMajorMinorVersion() {
+    if [[ -f "$JENKINS_WAR" ]]; then
+        local version major minor
+        version="$(java -jar "$JENKINS_WAR" --version)"
+        major="$(echo "$version" | cut -d '.' -f 1)"
+        minor="$(echo "$version" | cut -d '.' -f 2)"
+        echo "$major.$minor"
+    else
+        echo ""
+    fi
+}
+
+main() {
+    local plugin jenkinsVersion
+    local plugins=()
+
+    mkdir -p "$REF_DIR" || exit 1
+    rm -f "$FAILED"
+
+    # Read plugins from stdin or from the command line arguments
+    if [[ ($# -eq 0) ]]; then
+        while read -r line || [ "$line" != "" ]; do
+            # Remove leading/trailing spaces, comments, and empty lines
+            plugin=$(echo "${line}" | tr -d '\r' | sed -e 's/^[ \t]*//g' -e 's/[ \t]*$//g' -e 's/[ \t]*#.*$//g' -e '/^[ \t]*$/d')
+
+            # Avoid adding empty plugin into array
+            if [ ${#plugin} -ne 0 ]; then
+                plugins+=("${plugin}")
+            fi
+        done
+    else
+        plugins=("$@")
+    fi
+
+    # Create lockfile manually before first run to make sure any explicit version set is used.
+    echo "Creating initial locks..."
+    for plugin in "${plugins[@]}"; do
+        mkdir "$(getLockFile "${plugin%%:*}")"
+    done
+
+    echo "Analyzing war $JENKINS_WAR..."
+    bundledPlugins="$(bundledPlugins)"
+
+    echo "Registering preinstalled plugins..."
+    installedPlugins="$(installedPlugins)"
+
+    # Check if there's a version-specific update center, which is the case for LTS versions
+    jenkinsVersion="$(jenkinsMajorMinorVersion)"
+    if curl -fsL -o /dev/null "$JENKINS_UC/$jenkinsVersion"; then
+        JENKINS_UC_LATEST="$JENKINS_UC/$jenkinsVersion"
+        echo "Using version-specific update center: $JENKINS_UC_LATEST..."
+    else
+        JENKINS_UC_LATEST=
+    fi
+
+    echo "Downloading plugins..."
+    for plugin in "${plugins[@]}"; do
+        local reg='^([^:]+):?([^:]+)?:?([^:]+)?:?(http.+)?'
+        if [[ $plugin =~ $reg ]]; then
+            local pluginId="${BASH_REMATCH[1]}"
+            local version="${BASH_REMATCH[2]}"
+            local lock="${BASH_REMATCH[3]}"
+            local url="${BASH_REMATCH[4]}"
+            download "$pluginId" "$version" "${lock:-true}" "${url}" &
+        else
+          echo "Skipping the line '${plugin}' as it does not look like a reference to a plugin"
+        fi
+    done
+    wait
+
+    echo
+    echo "WAR bundled plugins:"
+    echo "${bundledPlugins}"
+    echo
+    echo "Installed plugins:"
+    installedPlugins
+
+    if [[ -f $FAILED ]]; then
+        echo "Some plugins failed to download!" "$(<"$FAILED")" >&2
+        exit 1
+    fi
+
+    echo "Cleaning up locks"
+    find "$REF_DIR" -regex ".*.lock" | while read -r filepath; do
+        rm -r "$filepath"
+    done
+
+}
+
+main "$@"

+ 83 - 0
plugins.txt

@@ -0,0 +1,83 @@
+bootstrap4-api:latest
+echarts-api:latest
+ace-editor:latest
+antisamy-markup-formatter:latest
+ant:latest
+apache-httpcomponents-client-4-api:latest
+authentication-tokens:latest
+bouncycastle-api:latest
+branch-api:latest
+build-timeout:latest
+cloudbees-folder:latest
+cobertura:latest
+code-coverage-api:latest
+command-launcher:latest
+credentials-binding:latest
+credentials:latest
+display-url-api:latest
+docker-commons:latest
+docker-workflow:latest
+durable-task:latest
+email-ext:latest
+git-client:latest
+github-api:latest
+github-branch-source:latest
+github:latest
+git:latest
+git-server:latest
+gradle:latest
+handlebars:latest
+jackson2-api:latest
+jdk-tool:latest
+jquery-detached:latest
+jsch:latest
+junit:latest
+ldap:latest
+localization-support:latest
+localization-zh-cn:latest
+lockable-resources:latest
+mailer:latest
+mapdb-api:latest
+matrix-auth:latest
+matrix-project:latest
+momentjs:latest
+pam-auth:latest
+pipeline-build-step:latest
+pipeline-github-lib:latest
+pipeline-graph-analysis:latest
+pipeline-input-step:latest
+pipeline-milestone-step:latest
+pipeline-model-api:latest
+pipeline-model-declarative-agent:latest
+pipeline-model-definition:latest
+pipeline-model-extensions:latest
+pipeline-rest-api:latest
+pipeline-stage-step:latest
+pipeline-stage-tags-metadata:latest
+pipeline-stage-view:latest
+plain-credentials:latest
+resource-disposer:latest
+scm-api:latest
+script-security:latest
+ssh-credentials:latest
+ssh-slaves:latest
+structs:latest
+subversion:latest
+timestamper:latest
+token-macro:latest
+trilead-api:latest
+workflow-aggregator:latest
+workflow-api:latest
+workflow-basic-steps:latest
+workflow-cps-global-lib:latest
+workflow-cps:latest
+workflow-durable-task-step:latest
+workflow-job:latest
+workflow-multibranch:latest
+workflow-scm-step:latest
+workflow-step-api:latest
+workflow-support:latest
+ws-cleanup:latest
+checks-api:latest
+snakeyaml-api:latest
+plugin-util-api:latest