├── book.json ├── logs └── README.md ├── backups └── README.md ├── scripts ├── scripts.cfg ├── container.cfg ├── mng.sh ├── rmi.sh ├── build.sh ├── stop.sh ├── start.sh ├── run.sh ├── logs.sh ├── rm.sh ├── backup.sh ├── restoreHot.sh ├── backupCold.sh ├── restoreConfiguration.sh └── restore.sh ├── .dockerignore ├── gitbook ├── advanced.md ├── manual.md ├── advanced │ ├── running_inside_google_cloud.md │ ├── backups_with_rsnapshot.md │ ├── backups_in_google_storage_buckets.md │ ├── logging_with_loggly.md │ └── hide_security_credentials.md ├── references.md ├── manual │ ├── use_vagrant.md │ ├── container_permissions.md │ ├── extend_image.md │ ├── image_building.md │ ├── env_variables.md │ └── use_bash_scripts.md ├── nginx_reverse_proxy.md ├── jenkins_command_line_interface.md └── persist_in_docker_volumes.md ├── examples ├── extendentrypoint │ ├── custom-entrypoint.sh │ └── Dockerfile ├── installtools │ └── Dockerfile ├── extension │ ├── Dockerfile │ └── jenkins-master-security.env ├── volumes │ └── docker-compose.yml └── build │ └── docker-compose.yml ├── groovy ├── setExecutorsNumber.groovy ├── purgeBuilds.groovy ├── checkForUser.groovy ├── enableLegacySecurity.groovy ├── setAdminEMail.groovy ├── purgeWorkspaces.groovy ├── setEMailSettings.groovy ├── setSlavesPort.groovy ├── enableAdminUserAndSecurity.groovy ├── removePlugins.groovy └── managePlugins.groovy ├── .gitignore ├── imagescripts ├── initexecutors.sh ├── initsecuritysettings.sh ├── clicreation.sh ├── initslaveport.sh ├── initadmin.sh ├── initplugins.sh ├── initemails.sh └── docker-entrypoint.sh ├── docker-compose.yml ├── LICENSE ├── SUMMARY.md ├── README.md ├── Vagrantfile ├── getting_jenkins_docker_ready.md └── Dockerfile /book.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /logs/README.md: -------------------------------------------------------------------------------- 1 | Logs will be placed here. -------------------------------------------------------------------------------- /backups/README.md: -------------------------------------------------------------------------------- 1 | Backups will be placed here. -------------------------------------------------------------------------------- /scripts/scripts.cfg: -------------------------------------------------------------------------------- 1 | readonly ROOT_DIR=$(cd ${CUR_DIR}/..; pwd) -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | backups 3 | logs 4 | scripts 5 | snapshots 6 | README.md 7 | -------------------------------------------------------------------------------- /gitbook/advanced.md: -------------------------------------------------------------------------------- 1 | # Advanced 2 | 3 | The advanced section has several articles on how to enhance the usage and experience of this image. -------------------------------------------------------------------------------- /examples/extendentrypoint/custom-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo 'Your code here!' 4 | exec /home/jenkins/docker-entrypoint.sh "$@" 5 | -------------------------------------------------------------------------------- /groovy/setExecutorsNumber.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | 3 | def instance = Jenkins.getInstance() 4 | 5 | instance.setNumExecutors(0) 6 | 7 | instance.save() 8 | -------------------------------------------------------------------------------- /examples/installtools/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM blacklabelops/jenkins 2 | MAINTAINER Your Name 3 | 4 | USER root 5 | RUN echo "Install Your Tools" 6 | USER jenkins 7 | -------------------------------------------------------------------------------- /gitbook/manual.md: -------------------------------------------------------------------------------- 1 | # Manual 2 | 3 | The manual describes: 4 | 5 | * How to configure the container using Docker environment variables. 6 | * Using the project's bash scripts. 7 | * Using the project along with Vagrant. -------------------------------------------------------------------------------- /groovy/purgeBuilds.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.* 2 | 3 | def jobs = Jenkins.instance.projects.collect { it.name } 4 | jobs.each { 5 | def jobi = Jenkins.instance.getItem( it ) 6 | jobi.getBuilds().each { it.delete() } 7 | } 8 | -------------------------------------------------------------------------------- /examples/extension/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM blacklabelops/jenkins 2 | MAINTAINER Steffen Bleul 3 | 4 | ADD jenkins-master-security.env /home/jenkins/jenkinssettings 5 | ENV JENKINS_ENV_FILE=/home/jenkins/jenkinssettings 6 | -------------------------------------------------------------------------------- /examples/extendentrypoint/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM blacklabelops/jenkins 2 | MAINTAINER Your Name 3 | 4 | USER root 5 | RUN echo "Install Your Tools" 6 | USER jenkins 7 | 8 | COPY custom-entrypoint.sh /home/jenkins/custom-entrypoint.sh 9 | ENTRYPOINT ["/home/jenkins/custom-entrypoint.sh"] 10 | CMD ["jenkins"] 11 | -------------------------------------------------------------------------------- /examples/volumes/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | # Jenkins Master 5 | jenkins: 6 | image: blacklabelops/jenkins 7 | container_name: jenkins 8 | ports: 9 | - "8080:8080" 10 | volumes: 11 | - jenkinsdata:/jenkins 12 | 13 | volumes: 14 | jenkinsdata: 15 | external: false 16 | -------------------------------------------------------------------------------- /examples/build/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | # Jenkins Master 5 | jenkins: 6 | build: 7 | context: ../../ 8 | dockerfile: Dockerfile 9 | args: 10 | JENKINS_VERSION: latest 11 | JENKINS_RELEASE: war-stable 12 | container_name: jenkins 13 | ports: 14 | - "8090:8080" 15 | -------------------------------------------------------------------------------- /groovy/checkForUser.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | import hudson.security.* 3 | 4 | def instance = Jenkins.getInstance() 5 | 6 | def hudsonRealm = new HudsonPrivateSecurityRealm(false) 7 | def users = hudsonRealm. getAllUsers() 8 | if (!users || users.empty) 9 | println "No Users" 10 | else 11 | println "Admin found" 12 | 13 | instance.save() 14 | -------------------------------------------------------------------------------- /groovy/enableLegacySecurity.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | import hudson.security.* 3 | 4 | def instance = Jenkins.getInstance() 5 | 6 | def hudsonRealm = new LegacySecurityRealm() 7 | instance.setSecurityRealm(hudsonRealm) 8 | 9 | def strategy = new LegacyAuthorizationStrategy() 10 | instance.setAuthorizationStrategy(strategy) 11 | 12 | instance.save() 13 | -------------------------------------------------------------------------------- /groovy/setAdminEMail.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | import java.util.logging.Logger 3 | 4 | def instance = Jenkins.getInstance() 5 | 6 | def jenkinsLocationConfiguration = JenkinsLocationConfiguration.get() 7 | 8 | jenkinsLocationConfiguration.setAdminAddress("Blacklabelops ") 9 | jenkinsLocationConfiguration.save() 10 | 11 | instance.save() 12 | -------------------------------------------------------------------------------- /groovy/purgeWorkspaces.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.* 2 | // For each project 3 | for(item in Hudson.instance.items) { 4 | // check that job is not building 5 | if(!item.isBuilding()) { 6 | println("Wiping out workspace of job "+item.name) 7 | item.doDoWipeOutWorkspace() 8 | } 9 | else { 10 | println("Skipping job "+item.name+", currently building") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /gitbook/advanced/running_inside_google_cloud.md: -------------------------------------------------------------------------------- 1 | # Running Inside Google Container Engine 2 | 3 | The following tutorial will show you how to use this container inside the Google Container Engine (GCE). 4 | 5 | The example project repository can be found here: [blacklabelops/gce-jenkins](https://github.com/blacklabelops/gce-jenkins) 6 | 7 | {% include "git+https://github.com/blacklabelops/gce-jenkins.git/README.md" %} 8 | -------------------------------------------------------------------------------- /groovy/setEMailSettings.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | 3 | def inst = Jenkins.getInstance() 4 | 5 | def desc = inst.getDescriptor("hudson.tasks.Mailer") 6 | 7 | desc.setSmtpAuth("user", "userpass") 8 | desc.setReplyToAddress("dummy@jenkins.bla") 9 | desc.setSmtpHost("smpt host") 10 | desc.setUseSsl(true) 11 | desc.setSmtpPort("2525") 12 | desc.setCharset("UTF-8") 13 | 14 | desc.save() 15 | inst.save() 16 | -------------------------------------------------------------------------------- /groovy/setSlavesPort.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | import java.util.logging.Logger 3 | 4 | def logger = Logger.getLogger("") 5 | def instance = Jenkins.getInstance() 6 | def current_slaveport = instance.getSlaveAgentPort() 7 | def defined_slaveport = 50000 8 | 9 | if (current_slaveport!=defined_slaveport) { 10 | instance.setSlaveAgentPort(defined_slaveport) 11 | logger.info("Slaveport set to " + defined_slaveport) 12 | } 13 | 14 | 15 | instance.save() 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ############################# 2 | # Jenkins backups # 3 | ############################# 4 | *.tar 5 | *.tar.gz 6 | *.tgz 7 | 8 | ############################# 9 | # Logs and temp files # 10 | ############################# 11 | *.log 12 | *.tmp 13 | *~ 14 | 15 | ############################# 16 | # OS generated files # 17 | ############################# 18 | .directory 19 | .DS_Store 20 | Thumbs.db 21 | .vagrant 22 | snapshots 23 | -------------------------------------------------------------------------------- /gitbook/references.md: -------------------------------------------------------------------------------- 1 | # References 2 | 3 | 4 | * [Jenkins Homepage](http://jenkins-ci.org/) 5 | * [Docker Homepage](https://www.docker.com/) 6 | * [Docker Compose](https://docs.docker.com/compose/) 7 | * [Docker Userguide](https://docs.docker.com/userguide/) 8 | * [Oracle Java8](https://java.com/de/download/) 9 | * [Vagrant](https://www.vagrantup.com/) 10 | * [Virtualbox](https://www.virtualbox.org/) 11 | * [Imagelayers.io](https://imagelayers.io/?images=blacklabelops%2Fjenkins:latest) 12 | -------------------------------------------------------------------------------- /groovy/enableAdminUserAndSecurity.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | import hudson.security.* 3 | 4 | def instance = Jenkins.getInstance() 5 | 6 | def hudsonRealm = new HudsonPrivateSecurityRealm(false) 7 | hudsonRealm.createAccount("jenkins", "swordfish") 8 | instance.setSecurityRealm(hudsonRealm) 9 | 10 | def strategy = new GlobalMatrixAuthorizationStrategy() 11 | strategy.add(Jenkins.ADMINISTER, "jenkins") 12 | instance.setAuthorizationStrategy(strategy) 13 | 14 | instance.save() 15 | -------------------------------------------------------------------------------- /imagescripts/initexecutors.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Initialization of Number of Executors 4 | # 5 | 6 | if [ -n "${JENKINS_MASTER_EXECUTORS}" ]; then 7 | if [ ! -d "${JENKINS_HOME}/init.groovy.d" ]; then 8 | mkdir ${JENKINS_HOME}/init.groovy.d 9 | fi 10 | cat > ${JENKINS_HOME}/init.groovy.d/setExecutors.groovy <<_EOF_ 11 | import jenkins.model.* 12 | import hudson.security.* 13 | 14 | def instance = Jenkins.getInstance() 15 | instance.setNumExecutors(${JENKINS_MASTER_EXECUTORS}) 16 | instance.save() 17 | _EOF_ 18 | fi 19 | -------------------------------------------------------------------------------- /groovy/removePlugins.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | import java.util.logging.Logger 3 | 4 | def logger = Logger.getLogger("") 5 | def installed = false 6 | def initialized = false 7 | 8 | def pluginParameter="amazon-ecs amazon-ecr awseb-deployment-plugin" 9 | def plugins = pluginParameter.split() 10 | logger.info("" + plugins) 11 | def instance = Jenkins.getInstance() 12 | def pm = instance.getPluginManager() 13 | 14 | plugins.each { 15 | logger.info("Checking " + it) 16 | def actPlugin = pm.getPlugin(it) 17 | if (!actPlugin) { 18 | logger.info("Plugin not found " + it) 19 | } else { 20 | actPlugin.disable() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /imagescripts/initsecuritysettings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Initialization of Default Security Settings 4 | # 5 | 6 | if [ ! -d "${JENKINS_HOME}/init.groovy.d" ]; then 7 | mkdir ${JENKINS_HOME}/init.groovy.d 8 | fi 9 | 10 | cat > ${JENKINS_HOME}/init.groovy.d/securitySettings.groovy <<_EOF_ 11 | import jenkins.model.* 12 | import java.util.logging.Logger 13 | def logger = Logger.getLogger("") 14 | logger.info("Security Settings") 15 | // SECURITY-170 16 | System.setProperty('hudson.model.ParametersAction.keepUndefinedParameters', 'true') 17 | // SECURITY-95 18 | System.setProperty('hudson.model.DirectoryBrowserSupport.CSP', '') 19 | _EOF_ 20 | -------------------------------------------------------------------------------- /imagescripts/clicreation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Creation of cli scripts 4 | # 5 | 6 | PARAMETER_TOKEN='"$@"' 7 | ENVIRONMENT_VARIABLE_TOKEN='${JENKINS_CLI_URL}' 8 | ENVIRONMENT_VARIABLE_SSH_TOKEN='${JENKINS_CLI_SSH}' 9 | 10 | cat > /usr/bin/jenkins-cli <<_EOF_ 11 | #!/bin/bash 12 | java -jar /usr/bin/jenkins/cli.jar ${PARAMETER_TOKEN} 13 | _EOF_ 14 | 15 | cat > /usr/bin/cli <<_EOF_ 16 | #!/bin/bash 17 | if [ -n "${ENVIRONMENT_VARIABLE_SSH_TOKEN}" ]; then 18 | java -jar /usr/bin/jenkins/cli.jar -s ${ENVIRONMENT_VARIABLE_TOKEN} -i ${ENVIRONMENT_VARIABLE_SSH_TOKEN} ${PARAMETER_TOKEN} 19 | else 20 | java -jar /usr/bin/jenkins/cli.jar -s ${ENVIRONMENT_VARIABLE_TOKEN} ${PARAMETER_TOKEN} 21 | fi 22 | _EOF_ 23 | -------------------------------------------------------------------------------- /imagescripts/initslaveport.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Initialization of Slave Port Number 4 | # 5 | 6 | if [ -n "${JENKINS_SLAVEPORT}" ]; then 7 | if [ ! -d "${JENKINS_HOME}/init.groovy.d" ]; then 8 | mkdir ${JENKINS_HOME}/init.groovy.d 9 | fi 10 | cat > ${JENKINS_HOME}/init.groovy.d/setSlaveport.groovy <<_EOF_ 11 | import jenkins.model.* 12 | import java.util.logging.Logger 13 | 14 | def logger = Logger.getLogger("") 15 | def instance = Jenkins.getInstance() 16 | def current_slaveport = instance.getSlaveAgentPort() 17 | def defined_slaveport = ${JENKINS_SLAVEPORT} 18 | 19 | if (current_slaveport!=defined_slaveport) { 20 | instance.setSlaveAgentPort(defined_slaveport) 21 | logger.info("Slaveport set to " + defined_slaveport) 22 | instance.save() 23 | } 24 | _EOF_ 25 | fi 26 | -------------------------------------------------------------------------------- /scripts/container.cfg: -------------------------------------------------------------------------------- 1 | #------------------ 2 | # CONTAINER VARIABLES 3 | #------------------ 4 | readonly CONTAINER_NAME="jenkins" 5 | readonly CONTAINER_VOLUME="/jenkins" 6 | readonly IMAGE_NAME="blacklabelops/jenkins" 7 | readonly HOST_PORT="8090" 8 | 9 | #------------------ 10 | # CONTAINER UTILITIES 11 | #------------------ 12 | readonly UTILITY_IMAGE="centos" 13 | 14 | #------------------ 15 | # COMMON VARIABLES 16 | #------------------ 17 | readonly FILE_TIMESTAMP='%Y-%m-%d-%H-%M-%S' 18 | 19 | #------------------ 20 | # BACKUP VARIABLES 21 | #------------------ 22 | readonly BACKUP_DIRECTORY="backups" 23 | readonly BACKUP_FILE_PREFIX='JenkinsBackup' 24 | 25 | #------------------ 26 | # LOGS VARIABLES 27 | #------------------ 28 | readonly LOGFILE_DIRECTORY="logs" 29 | readonly LOGFILE_FILE_PREFIX='JenkinsLogs' 30 | -------------------------------------------------------------------------------- /gitbook/manual/use_vagrant.md: -------------------------------------------------------------------------------- 1 | # Vagrant 2 | 3 | Vagrant is fabulous tool for pulling and spinning up virtual machines like docker with containers. I can configure my development and test environment and simply pull it online. And so can you! 4 | 5 | First install: 6 | 7 | * [Vagrant](https://www.vagrantup.com/) 8 | * [Virtualbox](https://www.virtualbox.org/) 9 | 10 | Change into the project folder and build the project on the spot! 11 | 12 | ~~~~ 13 | $ vagrant up 14 | $ vagrant ssh 15 | [vagrant@localhost ~]$ cd /vagrant 16 | [vagrant@localhost ~]$ docker-compose up 17 | ~~~~ 18 | 19 | > Jenkins will be available on localhost:9200 on the host machine. 20 | 21 | Vagrant does not leave any docker artifacts on your beloved desktop and the vagrant image can simply be destroyed and repulled if anything goes wrong. Test my project to your heart's content! -------------------------------------------------------------------------------- /imagescripts/initadmin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Initialization of Admin User 4 | # 5 | 6 | if [ -n "${JENKINS_ADMIN_USER}" ] && [ -n "${JENKINS_ADMIN_PASSWORD}" ]; then 7 | if [ ! -d "${JENKINS_HOME}/init.groovy.d" ]; then 8 | mkdir ${JENKINS_HOME}/init.groovy.d 9 | fi 10 | cat > ${JENKINS_HOME}/init.groovy.d/initAdmin.groovy <<_EOF_ 11 | import jenkins.model.* 12 | import hudson.security.* 13 | def instance = Jenkins.getInstance() 14 | def hudsonRealm = new HudsonPrivateSecurityRealm(false) 15 | def users = hudsonRealm.getAllUsers() 16 | if (!users || users.empty) { 17 | hudsonRealm.createAccount("${JENKINS_ADMIN_USER}", "${JENKINS_ADMIN_PASSWORD}") 18 | instance.setSecurityRealm(hudsonRealm) 19 | def strategy = new GlobalMatrixAuthorizationStrategy() 20 | strategy.add(Jenkins.ADMINISTER, "${JENKINS_ADMIN_USER}") 21 | instance.setAuthorizationStrategy(strategy) 22 | } 23 | instance.save() 24 | _EOF_ 25 | fi 26 | -------------------------------------------------------------------------------- /groovy/managePlugins.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | import java.util.logging.Logger 3 | 4 | def logger = Logger.getLogger("") 5 | def installed = false 6 | def initialized = false 7 | 8 | def pluginParameter="gitlab-plugin hipchat swarm" 9 | def plugins = pluginParameter.split() 10 | logger.info("" + plugins) 11 | def instance = Jenkins.getInstance() 12 | def pm = instance.getPluginManager() 13 | def uc = instance.getUpdateCenter() 14 | uc.updateAllSites() 15 | 16 | plugins.each { 17 | logger.info("Checking " + it) 18 | if (!pm.getPlugin(it)) { 19 | logger.info("Looking UpdateCenter for " + it) 20 | if (!initialized) { 21 | uc.updateAllSites() 22 | initialized = true 23 | } 24 | def plugin = uc.getPlugin(it) 25 | if (plugin) { 26 | logger.info("Installing " + it) 27 | plugin.deploy() 28 | installed = true 29 | } 30 | } 31 | } 32 | 33 | if (installed) { 34 | logger.info("Plugins installed, initializing a restart!") 35 | instance.save() 36 | instance.doSafeRestart() 37 | } 38 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | # Jenkins Master 5 | jenkins: 6 | image: blacklabelops/jenkins:alpine 7 | container_name: jenkins 8 | hostname: jenkins 9 | networks: 10 | - jenkinsnet 11 | ports: 12 | - "8090:8080" 13 | volumes: 14 | - jenkinsdata:/jenkins 15 | - jenkinslogs:/var/log 16 | env_file: 17 | - jenkins-master.env 18 | labels: 19 | com.blacklabelops.description: "Jenkins Continuous Integration System" 20 | com.blacklabelops.service: "jenkins-master" 21 | # Jenkins Slave 22 | slave: 23 | image: blacklabelops/swarm-jdk8 24 | networks: 25 | - jenkinsnet 26 | env_file: 27 | - jenkins-slave.env 28 | labels: 29 | com.blacklabelops.description: "Jenkins Swarm JDK-8 Slave" 30 | com.blacklabelops.service: "slave" 31 | com.blacklabelops.applications: "java maven gradle" 32 | 33 | volumes: 34 | jenkinsdata: 35 | external: false 36 | jenkinslogs: 37 | external: false 38 | 39 | networks: 40 | jenkinsnet: 41 | driver: bridge 42 | -------------------------------------------------------------------------------- /gitbook/advanced/backups_with_rsnapshot.md: -------------------------------------------------------------------------------- 1 | # Backups With Rsnapshot 2 | 3 | You can create automatic backups using [blacklabelops/rsnapshotd](https://github.com/blacklabelops/rsnapshot/tree/master/rsnapshot-cron). 4 | This side-car container uses rsnapshot to create snapshots of your jenkins volume periodically. 5 | 6 | Full documentation can be found here: [blacklabelops/rsnapshotd](https://github.com/blacklabelops/rsnapshot/tree/master/rsnapshot-cron) 7 | 8 | First fire up the Jenkins master: 9 | 10 | ~~~~ 11 | $ docker run -d -p 8090:8080 --name jenkins blacklabelops/jenkins 12 | ~~~~ 13 | 14 | Then start and attach the side-car backup container: 15 | 16 | ~~~~ 17 | $ docker run -d \ 18 | --volumes-from jenkins \ 19 | -v $(pwd)/snapshots/:/snapshots \ 20 | -e "CRON_HOURLY=* * * * *" \ 21 | -e "BACKUP_DIRECTORIES=/jenkins/ jenkins/" \ 22 | blacklabelops/rsnapshotd 23 | ~~~~ 24 | 25 | > Mounts all volumes from the running container and snapshots the volume /jenkins inside the local 26 | snapshot directory under `jenkins/`. Note: If you use Windows then you will have to replace $(pwd) 27 | with an abolute path. 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Steffen Bleul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /gitbook/manual/container_permissions.md: -------------------------------------------------------------------------------- 1 | # Container Permissions 2 | 3 | Simply: You can set user-id and group-id matching to a user and group from your host machine! 4 | 5 | Due to security considerations this image is not running in root mode! The Jenkins process user inside the container is `jenkins` and the user's group is `jenkins`. This project offers a simplified mechanism for user- and group-mapping. You can set the uid of the user and gid of the user's group during build time. 6 | 7 | The process permissions are relevant when using volumes and mounted folders from the host machine. Jenkins need read and write permissions on the host machine. You can set UID and GID of the Jenkin's process during build time! UID and GID should resemble credentials from your host machine. 8 | 9 | The following build arguments can be used: 10 | 11 | * CONTAINER_UID: Set the user-id of the Jenkins process. (default: 1000) 12 | * CONTAINER_GID: Set the group-id of the Jenkins process. (default: 1000) 13 | 14 | Example: 15 | 16 | ~~~~ 17 | $ docker build --build-arg CONTAINER_UID=2000 --build-arg CONTAINER_GID=2000 -t jenkins . 18 | ~~~~ 19 | 20 | > The container will write and read files with UID 2000 and GID 2000. 21 | -------------------------------------------------------------------------------- /gitbook/advanced/backups_in_google_storage_buckets.md: -------------------------------------------------------------------------------- 1 | # Backups In Google Storage Buckets 2 | 3 | You can periodically create backups and upload them to your [Google Storage Bucket](https://cloud.google.com/storage/). 4 | 5 | Full documentation of the backup container can be found hee: [blacklabelops/gcloud](https://github.com/blacklabelops/gcloud) 6 | 7 | First fire up the Jenkins master: 8 | 9 | ~~~~ 10 | $ docker run -d -p 8090:8080 --name jenkins blacklabelops/jenkins 11 | ~~~~ 12 | 13 | Then start and attach the [blacklabelops/gcloud](https://github.com/blacklabelops/gcloud) container! 14 | 15 | The required example crontab can be found here: [example-crontab-backup.txt](https://github.com/blacklabelops/gcloud/blob/master/example-crontab-backup.txt) 16 | 17 | ~~~~ 18 | $ docker run \ 19 | --volumes-from jenkins \ 20 | -v $(pwd)/backups/:/backups \ 21 | -v $(pwd)/logs/:/logs \ 22 | -e "GCLOUD_ACCOUNT=$(base64 auth.json)" \ 23 | -e "GCLOUD_CRON=$(base64 example-crontab-backup.txt)" \ 24 | blacklabelops/gcloud 25 | ~~~~ 26 | 27 | > Uses the authentication file auth.json and executed the crontab th°°at uploads archives to the specified cloud bucket. Logs and 28 | backups are available locally. 29 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [Getting Jenkins Cloud Ready](getting_jenkins_docker_ready.md) 5 | * [Manual](gitbook/manual.md) 6 | * [Building The Image](gitbook/manual/image_building.md) 7 | * [Jenkins Command Line Interface](gitbook/jenkins_command_line_interface.md) 8 | * [Persist In Docker Volumes](gitbook/persist_in_docker_volumes.md) 9 | * [Container Permissions](gitbook/manual/container_permissions.md) 10 | * [Environment Variables](gitbook/manual/env_variables.md) 11 | * [Using Bash Scripts](gitbook/manual/use_bash_scripts.md) 12 | * [Using Vagrant](gitbook/manual/use_vagrant.md) 13 | * [How To Extend This Image](gitbook/manual/extend_image.md) 14 | * [Advanced](gitbook/advanced.md) 15 | * [NGINX Reverse Proxy](gitbook/nginx_reverse_proxy.md) 16 | * [Running Inside Google Container Engine](gitbook/advanced/running_inside_google_cloud.md) 17 | * [Hiding Security Credentials](gitbook/advanced/hide_security_credentials.md) 18 | * [Custom Container Logging](gitbook/advanced/logging_with_loggly.md) 19 | * [Backups With Rsnapshot](gitbook/advanced/backups_with_rsnapshot.md) 20 | * [Backups In Google Storage Buckets](gitbook/advanced/backups_in_google_storage_buckets.md) 21 | * [References](gitbook/references.md) 22 | 23 | -------------------------------------------------------------------------------- /scripts/mng.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Start Docker container 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | # Helper functions 20 | err() { 21 | printf '%b\n' "" 22 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 23 | printf '%b\n' "" 24 | exit 1 25 | } >&2 26 | 27 | success() { 28 | printf '%b\n' "" 29 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 30 | printf '%b\n' "" 31 | } 32 | 33 | #------------------ 34 | # SCRIPT ENTRYPOINT 35 | #------------------ 36 | 37 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" container..." 38 | CONTAINER_ID=$(docker ps -qa --filter="name="$CONTAINER_NAME"") 39 | 40 | if [ -z "$CONTAINER_ID" ]; then 41 | err ""$CONTAINER_NAME" not found" 42 | fi 43 | 44 | docker run -it --rm --volumes-from ${CONTAINER_NAME} ${UTILITY_IMAGE} /bin/bash 45 | 46 | success "Container manage successful." 47 | -------------------------------------------------------------------------------- /examples/extension/jenkins-master-security.env: -------------------------------------------------------------------------------- 1 | # Setting up the admin account and basic security 2 | JENKINS_ADMIN_USER="jenkins" 3 | JENKINS_ADMIN_PASSWORD="swordfish" 4 | # Specify the Java VM parameters 5 | # See: http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html 6 | JAVA_VM_PARAMETERS="-Xmx1024m -Xms512m" 7 | # Number of executors on Jenkins master. 8 | JENKINS_MASTER_EXECUTORS="0" 9 | # Whitespace separated list of required plugins. 10 | # Example: gitlab-plugin hipchat swarm 11 | JENKINS_PLUGINS="swarm git" 12 | # Parameters for setting up HTTP. 13 | # Example: 14 | # JENKINS_KEYSTORE_PASSWORD=swordfish 15 | # JENKINS_CERTIFICATE_DNAME=CN=SBleul,OU=Blacklabelops,O=blacklabelops.com,L=Munich,S=Bavaria,C=D 16 | JENKINS_KEYSTORE_PASSWORD="keystoreswordfish" 17 | JENKINS_CERTIFICATE_DNAME="CN=SBleul,OU=Blacklabelops,O=blacklabelops.net,L=Munich,S=Bavaria,C=DE" 18 | # Jenkins port for accepting swarm slave connections 19 | JENKINS_SLAVEPORT="50000" 20 | # Jenkins startup parameters. 21 | # See: https://wiki.jenkins-ci.org/display/JENKINS/Starting+and+Accessing+Jenkins 22 | JENKINS_PARAMETERS="" 23 | # Jenkins Mail Setup 24 | SMTP_USER_NAME="" 25 | SMTP_USER_PASS="" 26 | SMTP_HOST="" 27 | SMTP_PORT="" 28 | SMTP_REPLYTO_ADDRESS="" 29 | SMTP_USE_SSL="" 30 | SMTP_CHARSET="" 31 | # Jenkins log file. Not necessary, because Jenkins logs to Docker. 32 | JENKINS_LOG_FILE="" 33 | -------------------------------------------------------------------------------- /gitbook/advanced/logging_with_loggly.md: -------------------------------------------------------------------------------- 1 | # Custom Container Logging 2 | 3 | ## Jenkins Logging 4 | 5 | This container does not write a logfile by default. It's considered bad practise as logs 6 | should be accessed by the command `docker logs`. There are use case where you want to 7 | have additional log files, e.g. my use case is to relay log to Loggly [Loggly Homepage](https://www.loggly.com/). 8 | I have added a routine for logging and it's activated by defining a logfile. 9 | 10 | Environment Variable: LOG_FILE 11 | 12 | Example for a separate volume with a logfile: 13 | 14 | ~~~~ 15 | $ docker run -d -p 8090:8080 \ 16 | -v $(pwd)/logs:/jenkinslogs \ 17 | -e "LOG_FILE=/jenkinslogs/jenkins.log" \ 18 | --name jenkins \ 19 | blacklabelops/jenkins 20 | ~~~~ 21 | 22 | > You can watch the log by typing `cat ./logs/jenkins.log`. 23 | 24 | ## Logging with Loggly 25 | 26 | Now lets hook up the container with my Loggly side-car container and relay the log to Loggly! The Full 27 | documentation of the loggly container can be found here: [blacklabelops/loggly](https://github.com/blacklabelops/fluentd/tree/master/fluentd-loggly) 28 | 29 | ~~~~ 30 | $ docker run -d \ 31 | --volumes-from jenkins \ 32 | -e "LOGS_DIRECTORIES=/jenkinslogs" \ 33 | -e "LOGGLY_TOKEN=3ere-23kkke-23j3oj-mmkme-343" \ 34 | -e "LOGGLY_TAG=jenkinslog" \ 35 | --name jenkinsloggly \ 36 | blacklabelops/loggly 37 | ~~~~ 38 | 39 | > Note: You need a valid Loggly Customer Key in order to log to Loggly. 40 | -------------------------------------------------------------------------------- /scripts/rmi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Remove Docker image 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | # Helper functions 20 | err() { 21 | printf '%b\n' "" 22 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 23 | printf '%b\n' "" 24 | exit 1 25 | } >&2 26 | 27 | success() { 28 | printf '%b\n' "" 29 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 30 | printf '%b\n' "" 31 | } 32 | 33 | lookForImage() { 34 | local IMAGE_LIST=$(docker images | awk '{print $1}') 35 | local IMAGE_FOUND="false" 36 | 37 | for image in $IMAGE_LIST 38 | do 39 | if [ $image = $IMAGE_NAME ]; then 40 | IMAGE_FOUND="true" 41 | fi 42 | done 43 | 44 | echo $IMAGE_FOUND 45 | } 46 | 47 | #------------------ 48 | # SCRIPT ENTRYPOINT 49 | #------------------ 50 | 51 | found=$(lookForImage) 52 | 53 | if [ $found = "false" ]; then 54 | err ""$IMAGE_NAME" not found" 55 | fi 56 | 57 | printf '%b\n' "" 58 | printf '%b\n' ":: Removing image..." 59 | 60 | docker rmi ${IMAGE_NAME} 61 | 62 | found=$(lookForImage) 63 | 64 | if [ $found = "true" ]; then 65 | err ""$IMAGE_NAME" still found, removing failed." 66 | fi 67 | 68 | success "Image removed successfully." 69 | 70 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Build Docker image 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | # Helper functions 20 | err() { 21 | printf '%b\n' "" 22 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 23 | printf '%b\n' "" 24 | exit 1 25 | } >&2 26 | 27 | success() { 28 | printf '%b\n' "" 29 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 30 | printf '%b\n' "" 31 | } 32 | 33 | lookForImage() { 34 | local IMAGE_LIST=$(docker images | awk '{print $1}') 35 | local IMAGE_FOUND="false" 36 | 37 | for image in $IMAGE_LIST 38 | do 39 | if [ $image = $IMAGE_NAME ]; then 40 | IMAGE_FOUND="true" 41 | fi 42 | done 43 | 44 | echo $IMAGE_FOUND 45 | } 46 | 47 | #------------------ 48 | # SCRIPT ENTRYPOINT 49 | #------------------ 50 | 51 | found=$(lookForImage) 52 | if [ $found = "true" ]; then 53 | err ""$IMAGE_NAME" does exist, cannot build" 54 | fi 55 | 56 | printf '%b\n' "" 57 | printf '%b\n' ":: Building image..." 58 | 59 | docker build -t ${IMAGE_NAME} . 60 | 61 | found=$(lookForImage) 62 | if [ $found = "false" ]; then 63 | err ""$IMAGE_NAME" not found, build failed" 64 | fi 65 | 66 | success "Image build successfully." 67 | 68 | -------------------------------------------------------------------------------- /scripts/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Stop Docker container 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | # Helper functions 20 | err() { 21 | printf '%b\n' "" 22 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 23 | printf '%b\n' "" 24 | exit 1 25 | } >&2 26 | 27 | success() { 28 | printf '%b\n' "" 29 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 30 | printf '%b\n' "" 31 | } 32 | 33 | #------------------ 34 | # SCRIPT ENTRYPOINT 35 | #------------------ 36 | 37 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" container..." 38 | CONTAINER_ID=$(docker ps -q --filter="name="$CONTAINER_NAME"") 39 | 40 | if [ -z "$CONTAINER_ID" ]; then 41 | err ""$CONTAINER_NAME" not running" 42 | fi 43 | 44 | printf '%b\n' "" 45 | printf '%b\n' ":: Stop container..." 46 | 47 | stop=$(docker stop ${CONTAINER_NAME}) 48 | if [[ "$?" -ne 0 ]]; then 49 | err "Could not stop "$CONTAINER_NAME" container" 50 | fi 51 | 52 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" docker container..." 53 | CONTAINER_ID=$(docker ps -q --filter="name="$CONTAINER_NAME"") 54 | 55 | if [ ! -z "$CONTAINER_ID" ]; then 56 | err ""$CONTAINER_NAME" still running" 57 | fi 58 | 59 | success "Container stopped successful." -------------------------------------------------------------------------------- /scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Start Docker container 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | # Helper functions 20 | err() { 21 | printf '%b\n' "" 22 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 23 | printf '%b\n' "" 24 | exit 1 25 | } >&2 26 | 27 | success() { 28 | printf '%b\n' "" 29 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 30 | printf '%b\n' "" 31 | } 32 | 33 | #------------------ 34 | # SCRIPT ENTRYPOINT 35 | #------------------ 36 | 37 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" container..." 38 | CONTAINER_ID=$(docker ps -q --filter="name="$CONTAINER_NAME"") 39 | 40 | if [ ! -z "$CONTAINER_ID" ]; then 41 | err ""$CONTAINER_NAME" already running" 42 | fi 43 | 44 | printf '%b\n' "" 45 | printf '%b\n' ":: start container..." 46 | 47 | start=$(docker start ${CONTAINER_NAME}) 48 | if [[ "$?" -ne 0 ]]; then 49 | err "Could not start "$CONTAINER_NAME" container" 50 | fi 51 | 52 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" docker container..." 53 | CONTAINER_ID=$(docker ps -q --filter="name="$CONTAINER_NAME"") 54 | 55 | if [ -z "$CONTAINER_ID" ]; then 56 | err ""$CONTAINER_NAME" not running" 57 | fi 58 | 59 | success "Container started successful." -------------------------------------------------------------------------------- /gitbook/manual/extend_image.md: -------------------------------------------------------------------------------- 1 | # How To Extend This Image 2 | 3 | # Add Your Tooling 4 | 5 | If you want to add your own tools and Dockerfile you will have to extend this image. 6 | 7 | This is an minimal Dockerfile to extend to install this image but keep it capabilities: 8 | 9 | ~~~~ 10 | FROM blacklabelops/jenkins 11 | MAINTAINER Your Name 12 | 13 | USER root 14 | RUN echo "Install Your Tools" 15 | USER jenkins 16 | ~~~~ 17 | 18 | > Switches to user root in order to be able to install tools then goes back to regular image user. 19 | 20 | # Write Your Own Entrypoint 21 | 22 | You can also write your own entrypoint if you want to extend capabilities, scripts and such. I have prepared an example in repository folder: [examples/extendentrypoint](https://github.com/blacklabelops/jenkins/blob/master/examples/extendentrypoint/) 23 | 24 | First extend the image in order to hook up your custom entrypoint. 25 | 26 | This is an minimal Dockerfile to install and trigger your own Dockerfile: 27 | 28 | ~~~~ 29 | FROM blacklabelops/jenkins 30 | MAINTAINER Your Name 31 | 32 | USER root 33 | RUN echo "Install Your Tools" 34 | USER jenkins 35 | 36 | COPY custom-entrypoint.sh /home/jenkins/custom-entrypoint.sh 37 | ENTRYPOINT ["/home/jenkins/custom-entrypoint.sh"] 38 | CMD ["jenkins"] 39 | ~~~~ 40 | 41 | > Note: `custom-entrypoint.sh` is your own entrypoint script. 42 | 43 | Your entrypoint must trigger the blacklabelops/jenkins entrypoint in order to keep the images functionality, e.g. environment variables. 44 | 45 | Example `custom-entrypoint.sh`: 46 | 47 | ~~~~ 48 | #!/bin/bash 49 | 50 | echo 'Your code here!' 51 | exec /home/jenkins/docker-entrypoint.sh "$@" 52 | ~~~~ 53 | -------------------------------------------------------------------------------- /gitbook/nginx_reverse_proxy.md: -------------------------------------------------------------------------------- 1 | # NGINX Reverse Proxy 2 | 3 | ## NGINX HTTP Proxy 4 | 5 | This is an example on running Jenkins behind NGINX with 2 Docker commands! 6 | 7 | First start Jenkins: 8 | 9 | ~~~~ 10 | $ docker run -d --name jenkins \ 11 | blacklabelops/jenkins 12 | ~~~~ 13 | 14 | > Note: Starting Jenkins without any port mapping. 15 | 16 | Then start NGINX: 17 | 18 | ~~~~ 19 | $ docker run -d \ 20 | -p 80:80 \ 21 | --name nginx \ 22 | --link jenkins:jenkins \ 23 | -e "SERVER1REVERSE_PROXY_LOCATION1=/" \ 24 | -e "SERVER1REVERSE_PROXY_PASS1=http://jenkins:8080/" \ 25 | blacklabelops/nginx 26 | ~~~~ 27 | 28 | > Jenkins will be available at http://192.168.99.100. 29 | 30 | ## NGINX HTTPS Proxy 31 | 32 | This is an example on running Jenkins behind NGINX-HTTPS with 2 Docker commands! 33 | 34 | Note: This is a self-signed certificate! Trusted certificates by letsencrypt are supported. Documentation can be found here: [blacklabelops/nginx](https://github.com/blacklabelops/nginx) 35 | 36 | First start Jenkins: 37 | 38 | ~~~~ 39 | $ docker run -d --name jenkins \ 40 | blacklabelops/jenkins 41 | ~~~~ 42 | 43 | Then start NGINX: 44 | 45 | ~~~~ 46 | $ docker run -d \ 47 | -p 443:443 \ 48 | --name nginx \ 49 | --link jenkins:jenkins \ 50 | -e "SERVER1REVERSE_PROXY_LOCATION1=/" \ 51 | -e "SERVER1REVERSE_PROXY_PASS1=hhttp://jenkins:8080/" \ 52 | -e "SERVER1CERTIFICATE_DNAME=/CN=CrustyClown/OU=SpringfieldEntertainment/O=crusty.springfield.com/L=Springfield/C=US" \ 53 | -e "SERVER1HTTPS_ENABLED=true" \ 54 | -e "SERVER1HTTP_ENABLED=false" \ 55 | blacklabelops/nginx 56 | ~~~~ 57 | 58 | > Jenkins will be available at https://192.168.99.100. -------------------------------------------------------------------------------- /scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Run Docker container 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | # Helper functions 20 | err() { 21 | printf '%b\n' "" 22 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 23 | printf '%b\n' "" 24 | exit 1 25 | } >&2 26 | 27 | success() { 28 | printf '%b\n' "" 29 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 30 | printf '%b\n' "" 31 | } 32 | 33 | #------------------ 34 | # SCRIPT ENTRYPOINT 35 | #------------------ 36 | 37 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" container..." 38 | CONTAINER_RETRY=$(docker ps -q --filter="name="$CONTAINER_NAME"") 39 | 40 | if [ ! -z "$CONTAINER_RETRY" ]; then 41 | printf '%b\n' " container found" 42 | err ""$CONTAINER_NAME" already running" 43 | fi 44 | 45 | printf '%b\n' "" 46 | printf '%b\n' ":: Run container..." 47 | 48 | run=$(docker run -d -p ${HOST_PORT}:8080 --name=""$CONTAINER_NAME"" ${IMAGE_NAME}) 49 | if [[ "$?" -ne 0 ]]; then 50 | err "Could not start "$CONTAINER_NAME" container" 51 | fi 52 | 53 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" docker container..." 54 | CONTAINER_ID=$(docker ps -q --filter="name="$CONTAINER_NAME"") 55 | 56 | if [ -z "$CONTAINER_ID" ]; then 57 | err ""$CONTAINER_NAME" container not found" 58 | fi 59 | 60 | printf '%b\n' " container found" 61 | success "Container running successful." 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dockerized Jenkins 2 | 3 | ## Supported tags and respective Dockerfile links 4 | 5 | | Distribution | Version | Tag | Dockerfile | 6 | |--------------|--------------|--------------|------------| 7 | | Alpine | 2.141 | latest, 2.141 | [Dockerfile](https://github.com/blacklabelops/jenkins/blob/master/Dockerfile) | 8 | | Alpine | stable 2.121.3 | 2.121.3 | [Dockerfile](https://github.com/blacklabelops/jenkins/blob/master/Dockerfile) | 9 | | Alpine | release candidate | rc | [Dockerfile](https://github.com/blacklabelops/jenkins/blob/master/Dockerfile) | 10 | | Alpine | stable release candidate | stable-rc | [Dockerfile](https://github.com/blacklabelops/jenkins/blob/master/Dockerfile) | 11 | 12 | > Older tags remain but are not supported/rebuild. 13 | 14 | # Make It Short 15 | 16 | ~~~~ 17 | $ docker run -d -p 80:8080 --name jenkins blacklabelops/jenkins 18 | ~~~~ 19 | 20 | # Passing Parameters 21 | 22 | You can run the Jenkins solely with command line parameters! 23 | 24 | Example: 25 | 26 | ~~~~ 27 | $ docker run \ 28 | -d -p 8090:8080 \ 29 | --name jenkins \ 30 | blacklabelops/jenkins --debug=9 31 | ~~~~ 32 | 33 | > Staring Jenkins with custom debug level. 34 | 35 | Example list parameters: 36 | 37 | ~~~~ 38 | $ docker run --rm blacklabelops/jenkins --help 39 | ~~~~ 40 | 41 | > Lists jenkins plugin parameters. 42 | 43 | Example printing Jenkins version: 44 | 45 | ~~~~ 46 | $ docker run --rm blacklabelops/jenkins --version 47 | ~~~~ 48 | 49 | > Prints the image's Jenkins version. 50 | 51 | # Build Slaves 52 | 53 | Build Slaves can be found here: [blacklabelops/swarm](https://github.com/blacklabelops/swarm) 54 | 55 | # Manual 56 | 57 | The detailed manual moved here: 58 | 59 | * [Gitbook blacklabelops/jenkins](https://www.gitbook.com/book/blacklabelops/jenkins) 60 | -------------------------------------------------------------------------------- /imagescripts/initplugins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Initialization of Plugins 4 | # 5 | 6 | jenkins_plugins="" 7 | 8 | DEFAULT_PLUGINS="docker-workflow ant build-timeout credentials-binding email-ext github-organization-folder gradle workflow-aggregator ssh-slaves subversion timestamper ws-cleanup" 9 | 10 | if [ -n "${JENKINS_PLUGINS}" ]; then 11 | JENKINS_PLUGINS=$JENKINS_PLUGINS" "$DEFAULT_PLUGINS 12 | else 13 | JENKINS_PLUGINS=$DEFAULT_PLUGINS 14 | fi 15 | 16 | if [ -n "${JENKINS_PLUGINS}" ]; then 17 | if [ ! -d "${JENKINS_HOME}/init.groovy.d" ]; then 18 | mkdir ${JENKINS_HOME}/init.groovy.d 19 | fi 20 | jenkins_plugins=${JENKINS_PLUGINS} 21 | cat > ${JENKINS_HOME}/init.groovy.d/loadPlugins.groovy <<_EOF_ 22 | import jenkins.model.* 23 | import java.util.logging.Logger 24 | def logger = Logger.getLogger("") 25 | def installed = false 26 | def initialized = false 27 | def pluginParameter="${jenkins_plugins}" 28 | def plugins = pluginParameter.split() 29 | logger.info("" + plugins) 30 | def instance = Jenkins.getInstance() 31 | def pm = instance.getPluginManager() 32 | def uc = instance.getUpdateCenter() 33 | plugins.each { 34 | logger.info("Checking " + it) 35 | if (!pm.getPlugin(it)) { 36 | logger.info("Looking UpdateCenter for " + it) 37 | if (!initialized) { 38 | uc.updateAllSites() 39 | initialized = true 40 | } 41 | def plugin = uc.getPlugin(it) 42 | if (plugin) { 43 | logger.info("Installing " + it) 44 | def installFuture = plugin.deploy() 45 | while(!installFuture.isDone()) { 46 | logger.info("Waiting for plugin install: " + it) 47 | sleep(3000) 48 | } 49 | installed = true 50 | } 51 | } 52 | } 53 | if (installed) { 54 | logger.info("Plugins installed, initializing a restart!") 55 | instance.save() 56 | instance.restart() 57 | } 58 | _EOF_ 59 | fi 60 | -------------------------------------------------------------------------------- /gitbook/jenkins_command_line_interface.md: -------------------------------------------------------------------------------- 1 | # Jenkins Command Line Interface 2 | 3 | This image contains the Jenkins CLI. You can run the cli easily against the Jenkins server locally or remote. 4 | 5 | Example: 6 | 7 | First start the server: 8 | 9 | ~~~~ 10 | $ docker run -d -p 80:8080 --name jenkins blacklabelops/jenkins 11 | ~~~~ 12 | 13 | > Jenkins will be available at http://yourdockerhost:8090. 14 | 15 | ## Running CLI Locally 16 | 17 | You can enter the running jenkins container and execute the client against the server! 18 | 19 | ~~~~ 20 | $ docker exec jenkins cli 21 | ~~~~ 22 | 23 | > Will list the help of the Jenkins cli 24 | 25 | ## Running CLI Against Server 26 | 27 | You can run the CLI against any Jenkins server! 28 | 29 | ~~~~ 30 | $ docker run -it --rm -e "JENKINS_CLI_URL=http://jenkins.example.com" blacklabelops/jenkins cli 31 | ~~~~ 32 | 33 | > Will run the cli against the Jenkins server defined in JENKINS_CLI_URL 34 | 35 | You can also use the non-parameterized jenkins-cli command and run against any network available Jenkins! 36 | 37 | ~~~~ 38 | $ docker run -it --rm blacklabelops/jenkins jenkins-cli -s http://jenkins.example.com 39 | ~~~~ 40 | 41 | > Will run the cli with any given and valid jenkins cli parameter. 42 | 43 | ## Running CLI Remotely 44 | 45 | You can run the cli against a linked jenkins server! 46 | 47 | ~~~~ 48 | $ docker exec --link jenkins:jenkins -e "JENKINS_CLI_URL=http://jenkins:8080" blacklabelops/jenkins cli 49 | ~~~~ 50 | 51 | > Will run the cli against the linked Jenkins container 52 | 53 | ## SSH Authentication 54 | 55 | You can define an SSH authentication file with the environment variable JENKINS_CLI_SSH! 56 | 57 | ~~~~ 58 | $ docker exec --link jenkins:jenkins -v myauthentication.pem:/sshfiles/tokenfile.pem -e "JENKINS_CLI_SSH=/sshfiles/tokenfile.pem" -e "JENKINS_CLI_URL=http://jenkins:8080" blacklabelops/jenkins cli 59 | ~~~~ 60 | 61 | > Will trigger cli with authentication. -------------------------------------------------------------------------------- /imagescripts/initemails.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Initialization of EMail Settings 4 | # 5 | 6 | smtp_replyto_address="dummy@example.com" 7 | smtp_use_ssl="true" 8 | smtp_charset="UTF-8" 9 | 10 | if [ -n "${SMTP_REPLYTO_ADDRESS}" ]; then 11 | smtp_replyto_address=${SMTP_REPLYTO_ADDRESS} 12 | fi 13 | 14 | if [ -n "${SMTP_USE_SSL}" ]; then 15 | smtp_use_ssl=${SMTP_USE_SSL} 16 | fi 17 | 18 | if [ -n "${SMTP_CHARSET}" ]; then 19 | smtp_charset=${SMTP_CHARSET} 20 | fi 21 | 22 | if [ -n "${SMTP_USER_NAME}" ] && [ -n "${SMTP_USER_PASS}" ] && [ -n "${SMTP_HOST}" ] && [ -n "${SMTP_PORT}" ]; then 23 | if [ ! -d "${JENKINS_HOME}/init.groovy.d" ]; then 24 | mkdir ${JENKINS_HOME}/init.groovy.d 25 | fi 26 | smtp_user_name=${SMTP_USER_NAME} 27 | smtp_user_pass=${SMTP_USER_PASS} 28 | smtp_host=${SMTP_HOST} 29 | smtp_port=${SMTP_PORT} 30 | 31 | cat > ${JENKINS_HOME}/init.groovy.d/initSMTP.groovy <<_EOF_ 32 | import jenkins.model.* 33 | 34 | def inst = Jenkins.getInstance() 35 | def desc = inst.getDescriptor("hudson.tasks.Mailer") 36 | 37 | desc.setSmtpAuth("${smtp_user_name}", "${smtp_user_pass}") 38 | desc.setReplyToAddress("${smtp_replyto_address}") 39 | desc.setSmtpHost("${smtp_host}") 40 | desc.setUseSsl(${smtp_use_ssl}) 41 | desc.setSmtpPort("${smtp_port}") 42 | desc.setCharset("${smtp_charset}") 43 | 44 | desc.save() 45 | inst.save() 46 | _EOF_ 47 | fi 48 | 49 | if [ -n "${JENKINS_ADMIN_EMAIL}" ]; then 50 | if [ ! -d "${JENKINS_HOME}/init.groovy.d" ]; then 51 | mkdir ${JENKINS_HOME}/init.groovy.d 52 | fi 53 | cat > ${JENKINS_HOME}/init.groovy.d/initAdminEMail.groovy <<_EOF_ 54 | import jenkins.model.* 55 | import java.util.logging.Logger 56 | 57 | def instance = Jenkins.getInstance() 58 | def jenkinsLocationConfiguration = JenkinsLocationConfiguration.get() 59 | 60 | jenkinsLocationConfiguration.setAdminAddress("${JENKINS_ADMIN_EMAIL}") 61 | 62 | jenkinsLocationConfiguration.save() 63 | instance.save() 64 | _EOF_ 65 | fi 66 | -------------------------------------------------------------------------------- /scripts/logs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Download a log file from Docker container 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | readonly LOGS_DIR=${ROOT_DIR}/${LOGFILE_DIRECTORY} 20 | 21 | # Helper functions 22 | err() { 23 | printf '%b\n' "" 24 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 25 | printf '%b\n' "" 26 | exit 1 27 | } >&2 28 | 29 | success() { 30 | printf '%b\n' "" 31 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 32 | printf '%b\n' "" 33 | } 34 | 35 | 36 | #------------------ 37 | # SCRIPT ENTRYPOINT 38 | #------------------ 39 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" docker container..." 40 | CONTAINER_ID=$(docker ps -aq --filter="name="$CONTAINER_NAME"") 41 | 42 | if [ -z "$CONTAINER_ID" ]; then 43 | err ""$CONTAINER_NAME" container not found" 44 | fi 45 | 46 | # TODO: clarify whether we need to notify when container is running or stopped 47 | printf '%b\n' " container found" 48 | printf '%b\n' "" 49 | printf '%b\n' ":: Downloading logs from container..." 50 | 51 | # make sure logs directory exists 52 | if [ ! -d "${LOGS_DIR}" ]; then 53 | mkdir -p ${LOGS_DIR} 54 | fi 55 | 56 | log_filename=${LOGFILE_FILE_PREFIX}-$(date +$FILE_TIMESTAMP).log 57 | $(docker logs ${CONTAINER_ID} > ${LOGS_DIR}/${log_filename}) 58 | if [[ "$?" -ne 0 ]]; then 59 | err "Command 'docker logs' failed" 60 | fi 61 | 62 | printf '%b\n' " logs directory: ${LOGS_DIR}" 63 | printf '%b\n' " log filename : ${log_filename}" 64 | 65 | success "Downloading complete successful." 66 | 67 | -------------------------------------------------------------------------------- /scripts/rm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Remove Docker container 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | # Helper functions 20 | err() { 21 | printf '%b\n' "" 22 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 23 | printf '%b\n' "" 24 | exit 1 25 | } >&2 26 | 27 | success() { 28 | printf '%b\n' "" 29 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 30 | printf '%b\n' "" 31 | } 32 | 33 | 34 | #------------------ 35 | # SCRIPT ENTRYPOINT 36 | #------------------ 37 | 38 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" docker container..." 39 | CONTAINER_ID=$(docker ps -aq --filter="name="$CONTAINER_NAME"") 40 | 41 | if [ -z "$CONTAINER_ID" ]; then 42 | err ""$CONTAINER_NAME" container not found" 43 | fi 44 | 45 | # TODO: clarify whether we need to notify when container is running or stopped 46 | printf '%b\n' " container is found" 47 | printf '%b\n' "" 48 | printf '%b\n' ":: Killing running container..." 49 | 50 | # kill running container 51 | docker kill ${CONTAINER_NAME} 52 | 53 | printf '%b\n' "" 54 | printf '%b\n' ":: Removing container..." 55 | 56 | # remove container 57 | stopped=$(docker rm -v ${CONTAINER_NAME}) 58 | if [[ "$?" -ne 0 ]]; then 59 | err "Could not remove "$CONTAINER_NAME" container" 60 | fi 61 | 62 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" container..." 63 | CONTAINER_RETRY=$(docker ps -aq --filter="name="$CONTAINER_NAME"") 64 | 65 | 66 | if [ ! -z "$CONTAINER_RETRY" ]; then 67 | err ""$CONTAINER_NAME" container removal failed" 68 | fi 69 | 70 | success "Removal complete successful." -------------------------------------------------------------------------------- /gitbook/manual/image_building.md: -------------------------------------------------------------------------------- 1 | # Building The Image 2 | 3 | ## Project Checkout 4 | 5 | First step: Check out this project from github! 6 | 7 | Repository location: [blacklabelops/jenkins](https://github.com/blacklabelops/jenkins) 8 | 9 | > Puts the Dockerfile in your local directory. 10 | 11 | ## Choose The Release 12 | 13 | Second step: Choose between Long-Term Support (LTS) Release or latest version release. 14 | 15 | Jenkins comes in two flavors. The LTS release is the best for your stable environment as its proven and tested. The release cycle is long term so you do not have to update often. The latest version is perfect if you want to tinker with the latest features. 16 | 17 | Here you can see the list of latest releases: [Release List](http://mirrors.jenkins-ci.org/war/) 18 | 19 | Here you can see the list of LTS releases: [Long-Term Support Release List](http://mirrors.jenkins-ci.org/war-stable/) 20 | 21 | ## Build The Image 22 | 23 | Third step: Build the image 24 | 25 | The build process can take two arguments: 26 | 27 | * JENKINS_RELEASE: Takes keyword `war-stable` for LTS releases and `war` otherwise. Default is `war`. 28 | * JENKINS_VERSION: Takes keyword `latest` or specific Jenkins version number. Default is `latest`. 29 | 30 | Examples: 31 | 32 | Build image with the latest Jenkins release: 33 | 34 | ~~~~ 35 | $ docker build -t blacklabelops/jenkins . 36 | ~~~~ 37 | 38 | > Note: Dockerfile must be inside the current directory! 39 | 40 | Build image with the latest Jenkins LTS release: 41 | 42 | ~~~~ 43 | $ docker build --build-arg JENKINS_RELEASE=war-stable -t blacklabelops/jenkins . 44 | ~~~~ 45 | 46 | > Note: Dockerfile must be inside the current directory! 47 | 48 | Build image with a specific Jenkins LTS release: 49 | 50 | ~~~~ 51 | $ docker build --build-arg JENKINS_RELEASE=war-stable --build-arg JENKINS_VERSION=1.625.3 -t blacklabelops/jenkins . 52 | ~~~~ 53 | 54 | > Note: Dockerfile must be inside the current directory! 55 | 56 | ## Using Docker Compose 57 | 58 | A minimal Docker-Compose file for building the image can be found in file `docker-compose.yml` inside the repository directory `examples/build`. 59 | 60 | The build configuration with arguments are specified inside the following area: 61 | 62 | ~~~~ 63 | jenkins: 64 | build: 65 | context: ../../ 66 | dockerfile: Dockerfile 67 | args: 68 | JENKINS_VERSION: latest 69 | JENKINS_RELEASE: war-stable 70 | ~~~~ 71 | 72 | > Adjust JENKINS_VERSION and JENKINS_RELEASE for your personal needs. 73 | 74 | Build the latest LTS release with docker-compose: 75 | 76 | ~~~~ 77 | $ cd examples/build 78 | $ docker-compose build 79 | ~~~~ 80 | -------------------------------------------------------------------------------- /gitbook/persist_in_docker_volumes.md: -------------------------------------------------------------------------------- 1 | # Persist Data In Docker Volumes 2 | 3 | Docker offers Docker volumes to separate your precious data from containers. You can remove and replace your container without losing any data. 4 | 5 | Firstly, create a volume: 6 | 7 | ~~~~ 8 | $ docker volume create --name jenkins_data 9 | ~~~~ 10 | 11 | > Note: The volumes name is `jenkins_data`. You can also check with `docker volume ls`. 12 | 13 | Secondly, start Jenkins and mount the newly created volume: 14 | 15 | ~~~~ 16 | $ docker run -d \ 17 | -p 8090:8080 \ 18 | -v jenkins_data:/jenkins \ 19 | --name jenkins \ 20 | blacklabelops/jenkins 21 | ~~~~ 22 | 23 | > Note: Must be always mounted at `/jenkins`; the container's fixed data directory. 24 | 25 | ##You want to check what's written inside your volume? 26 | 27 | You can check the volume's content from your running Jenkins: 28 | 29 | ~~~~ 30 | $ docker exec -it jenkins bash 31 | ... you operations here.... 32 | ~~~~ 33 | 34 | > Connects and runs bash inside your running Jenkins. You will be directed to the directory `/jenkins` because it's defined as the container's workfolder. 35 | 36 | You can check with a separate container: 37 | 38 | ~~~~ 39 | $ docker run -it --rm \ 40 | -v jenkins_data:/jenkins \ 41 | blacklabelops/alpine bash 42 | $ cd /jenkins 43 | ... you operations here.... 44 | ~~~~ 45 | 46 | > This container will mount the volume regardless if your Jenkins is still running! Please bear this in mind. Especially backups can be inconsistent when Jenkins is still running. 47 | 48 | ## Read Only Volume 49 | 50 | Docker's default for the volume parameter `-v` is read and write access. There's also a read-only mode. 51 | 52 | Example: 53 | 54 | ~~~~ 55 | $ docker run -it --rm \ 56 | -v jenkins_data:/jenkins:ro \ 57 | blacklabelops/alpine bash 58 | $ cd /jenkins 59 | ... you operations here.... 60 | ~~~~ 61 | 62 | > The volume will be available in read-only mode. 63 | 64 | ## Using Docker Compose 65 | 66 | A minimal Docker-Compose file for using volumes can be found in file `docker-compose.yml` inside the repository directory [examples/build](https://github.com/blacklabelops/jenkins/tree/master/examples/volumes). 67 | 68 | The file looks like this: 69 | 70 | ~~~~ 71 | version: '2' 72 | 73 | services: 74 | # Jenkins Master 75 | jenkins: 76 | image: blacklabelops/jenkins 77 | container_name: jenkins 78 | ports: 79 | - "8080:8080" 80 | volumes: 81 | - jenkinsdata:/jenkins 82 | 83 | volumes: 84 | jenkinsdata: 85 | external: false 86 | ~~~~ 87 | 88 | Just start up docker-compose, volumes will be managed on-the-fly: 89 | 90 | ~~~~ 91 | $ docker-compose up -d 92 | ~~~~ 93 | -------------------------------------------------------------------------------- /scripts/backup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Backup docker volume ["/jenkins"] from docker container. 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | readonly BACKUP_DIR=${ROOT_DIR}/${BACKUP_DIRECTORY} 20 | readonly BACKUP_CONTAINER="bckp_for_volume" 21 | 22 | # Helper functions 23 | err() { 24 | printf '%b\n' "" 25 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 26 | printf '%b\n' "" 27 | exit 1 28 | } >&2 29 | 30 | success() { 31 | printf '%b\n' "" 32 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 33 | printf '%b\n' "" 34 | } 35 | 36 | checkRunningBackup() { 37 | printf '%b\n' ":: Searching for running backup container..." 38 | CONTAINER_SEARCH=$(docker ps -q --filter="name="$BACKUP_CONTAINER"") 39 | 40 | if [ ! -z "$CONTAINER_SEARCH" ]; then 41 | printf '%b\n' " container is found" 42 | err "backup is already running" 43 | fi 44 | } 45 | 46 | cleaningBusybox() { 47 | printf '%b\n' ":: Searching for backup container..." 48 | CONTAINER_SEARCH=$(docker ps -aq --filter="name="$BACKUP_CONTAINER"") 49 | 50 | if [ ! -z "$CONTAINER_SEARCH" ]; then 51 | printf '%b\n' " backup container found" 52 | printf '%b\n' " cleaning container" 53 | # remove container 54 | docker rm ${BACKUP_CONTAINER} 55 | fi 56 | } 57 | 58 | #------------------ 59 | # SCRIPT ENTRYPOINT 60 | #------------------ 61 | 62 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" docker container..." 63 | CONTAINER_ID=$(docker ps -aq --filter="name="$CONTAINER_NAME"") 64 | 65 | if [ -z "$CONTAINER_ID" ]; then 66 | err ""$CONTAINER_NAME" container not found" 67 | fi 68 | 69 | printf '%b\n' " container found" 70 | printf '%b\n' "" 71 | printf '%b\n' ":: Backuping "$CONTAINER_VOLUME" folder from container..." 72 | 73 | # make sure backups directory exists 74 | if [ ! -d "${BACKUP_DIR}" ]; then 75 | err ""$BACKUP_DIR" not found" 76 | fi 77 | 78 | checkRunningBackup 79 | 80 | cleaningBusybox 81 | 82 | printf '%b\n' ":: Starting backup..." 83 | 84 | backup_filename=${BACKUP_FILE_PREFIX}-$(date +$FILE_TIMESTAMP).tar 85 | $(docker run --name=""$BACKUP_CONTAINER"" --rm --volumes-from ${CONTAINER_NAME} -v ${BACKUP_DIR}:/backup busybox tar cf /backup/${backup_filename} ${CONTAINER_VOLUME}) 86 | if [[ "$?" -ne 0 ]]; then 87 | err "Backup failed" 88 | fi 89 | 90 | cleaningBusybox 91 | 92 | printf '%b\n' " backup directory: ${BACKUP_DIR}" 93 | printf '%b\n' " backup file : ${backup_filename}" 94 | 95 | success "Backup complete" 96 | 97 | -------------------------------------------------------------------------------- /gitbook/advanced/hide_security_credentials.md: -------------------------------------------------------------------------------- 1 | # Hiding Security Credentials 2 | 3 | Hiding Environment Variables! This container can initialize with environment variables from a file. 4 | 5 | * If you prefer specifying your default password inside a file rather then inside your docker-compose file. 6 | * This way the password is also hidden from docker and the command **docker inspect**. 7 | * You can reconfigure the container without removing the container. 8 | 9 | The environment variable JENKINS_ENV_FILE tells the entryscript where to find the environment variables. 10 | 11 | Example: 12 | 13 | ~~~~ 14 | $ docker run --name jenkins \ 15 | -e "JENKINS_ENV_FILE=/home/jenkins/envs/myenvs.env" \ 16 | -v $(pwd)/myenvs.env:/home/jenkins/envs/myenvs.env \ 17 | -p 8080:8080 \ 18 | blacklabelops/jenkins 19 | ~~~~ 20 | 21 | > Mounts the local environment variable file myenvs.env inside the container. (file must have access rights for userid:groupid 1000:1000) 22 | 23 | How do you get the file inside the container? 24 | 25 | * Use the command **docker cp** in order to copy the file inside an already initialized container. 26 | * Extend the container with a new Dockerfile. Example can be found here: [Example-Dockerfile](https://github.com/blacklabelops/jenkins/blob/master/examples/extension/Dockerfile) 27 | * Put the file inside a data-container and mount it with the **--volumes-from** directive. 28 | 29 | ## Example Extension Dockerfile 30 | 31 | ~~~~ 32 | FROM blacklabelops/jenkins 33 | MAINTAINER Steffen Bleul 34 | 35 | ADD jenkins-master-security.env /home/jenkins/jenkinssettings 36 | ENV JENKINS_ENV_FILE=/home/jenkins/jenkinssettings 37 | ~~~~ 38 | 39 | ## Example Environment File 40 | 41 | ~~~~ 42 | # Setting up the admin account and basic security 43 | JENKINS_ADMIN_USER="jenkins" 44 | JENKINS_ADMIN_PASSWORD="swordfish" 45 | # Specify the Java VM parameters 46 | # See: http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html 47 | JAVA_VM_PARAMETERS="-Xmx1024m -Xms512m" 48 | # Number of executors on Jenkins master. 49 | JENKINS_MASTER_EXECUTORS="0" 50 | # Whitespace separated list of required plugins. 51 | # Example: gitlab-plugin hipchat swarm 52 | JENKINS_PLUGINS="swarm git" 53 | # Parameters for setting up HTTP. 54 | # Example: 55 | # JENKINS_KEYSTORE_PASSWORD=swordfish 56 | # JENKINS_CERTIFICATE_DNAME=CN=SBleul,OU=Blacklabelops,O=blacklabelops.com,L=Munich,S=Bavaria,C=D 57 | JENKINS_KEYSTORE_PASSWORD="keystoreswordfish" 58 | JENKINS_CERTIFICATE_DNAME="CN=SBleul,OU=Blacklabelops,O=blacklabelops.net,L=Munich,S=Bavaria,C=DE" 59 | # Jenkins port for accepting swarm slave connections 60 | JENKINS_SLAVEPORT="50000" 61 | # Jenkins startup parameters. 62 | # See: https://wiki.jenkins-ci.org/display/JENKINS/Starting+and+Accessing+Jenkins 63 | JENKINS_PARAMETERS="" 64 | # Jenkins Mail Setup 65 | SMTP_USER_NAME="" 66 | SMTP_USER_PASS="" 67 | SMTP_HOST="" 68 | SMTP_PORT="" 69 | SMTP_REPLYTO_ADDRESS="" 70 | SMTP_USE_SSL="" 71 | SMTP_CHARSET="" 72 | # Jenkins log file. Not necessary, because Jenkins logs to Docker. 73 | JENKINS_LOG_FILE="" 74 | ~~~~ 75 | -------------------------------------------------------------------------------- /imagescripts/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # A helper script for ENTRYPOINT. 4 | # 5 | # If first CMD argument is 'jenkins', then the script will bootstrap Jenkins 6 | # If CMD argument is overriden and not 'jenkins', then the user wants to run 7 | # his own process. 8 | 9 | set -o errexit 10 | 11 | [[ ${DEBUG} == true ]] && set -x 12 | 13 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 14 | 15 | source $CUR_DIR/clicreation.sh 16 | source $CUR_DIR/initsecuritysettings.sh 17 | 18 | if [ -n "${JENKINS_DELAYED_START}" ]; then 19 | sleep ${JENKINS_DELAYED_START} 20 | fi 21 | 22 | if [ -n "${JENKINS_ENV_FILE}" ]; then 23 | source ${JENKINS_ENV_FILE} 24 | fi 25 | 26 | java_vm_parameters=${JAVA_VM_PARAMETERS} 27 | jenkins_parameters="" 28 | 29 | if [ "${JENKINS_PRODUCTION_SETTINGS}" = 'true' ]; then 30 | java_vm_parameters="-Xms4096m -Xmx4096m -XX:NewSize=2048m -XX:MaxNewSize=2048m -XX:ParallelGCThreads=4 -XX:ConcGCThreads=4 -Dhudson.slaves.ChannelPinger.pingInterval=-1 -Dhudson.security.ExtendedReadPermission=true -Dgroovy.use.classvalue=true" 31 | fi 32 | 33 | if [ -n "${JENKINS_PARAMETERS}" ]; then 34 | jenkins_parameters=${JENKINS_PARAMETERS} 35 | fi 36 | 37 | 38 | 39 | if [ "$1" = 'jenkins' ] || [[ "$1" == '--'* ]] ; then 40 | 41 | source $CUR_DIR/initexecutors.sh 42 | source $CUR_DIR/initslaveport.sh 43 | source $CUR_DIR/initplugins.sh 44 | source $CUR_DIR/initemails.sh 45 | source $CUR_DIR/initadmin.sh 46 | 47 | if [ -n "${JENKINS_KEYSTORE_PASSWORD}" ] && [ -n "${JENKINS_CERTIFICATE_DNAME}" ]; then 48 | if [ ! -f "${JENKINS_HOME}/jenkins_keystore.jks" ]; then 49 | ${JAVA_HOME}/bin/keytool -genkey -alias jenkins_master -keyalg RSA -keystore ${JENKINS_HOME}/jenkins_keystore.jks -storepass ${JENKINS_KEYSTORE_PASSWORD} -keypass ${JENKINS_KEYSTORE_PASSWORD} --dname "${JENKINS_CERTIFICATE_DNAME}" 50 | fi 51 | jenkins_parameters=${jenkins_parameters}' --httpPort=-1 --httpsPort=8080 --httpsKeyStore='${JENKINS_HOME}'/jenkins_keystore.jks --httpsKeyStorePassword='${JENKINS_KEYSTORE_PASSWORD} 52 | fi 53 | 54 | log_parameter="" 55 | 56 | if [ -n "${JENKINS_LOG_FILE}" ]; then 57 | log_dir=$(dirname ${JENKINS_LOG_FILE}) 58 | log_file=$(basename ${JENKINS_LOG_FILE}) 59 | if [ ! -d "${log_dir}" ]; then 60 | mkdir -p ${log_dir} 61 | fi 62 | if [ ! -f "${JENKINS_LOG_FILE}" ]; then 63 | touch ${JENKINS_LOG_FILE} 64 | fi 65 | log_parameter=" --logfile="${JENKINS_LOG_FILE} 66 | fi 67 | 68 | unset JENKINS_ADMIN_USER 69 | unset JENKINS_ADMIN_PASSWORD 70 | unset JENKINS_KEYSTORE_PASSWORD 71 | unset SMTP_USER_NAME 72 | unset SMTP_USER_PASS 73 | 74 | if [ "$1" = 'jenkins' ] ; then 75 | exec /usr/bin/java -Dfile.encoding=UTF-8 -Djenkins.install.runSetupWizard=false ${java_vm_parameters} -jar /usr/bin/jenkins/jenkins.war ${jenkins_parameters}${log_parameter} 76 | else 77 | exec /usr/bin/java -Dfile.encoding=UTF-8 -Djenkins.install.runSetupWizard=false ${java_vm_parameters} -jar /usr/bin/jenkins/jenkins.war ${jenkins_parameters}${log_parameter} "$@" 78 | fi 79 | else 80 | exec "$@" 81 | fi 82 | -------------------------------------------------------------------------------- /scripts/restoreHot.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Restore docker volume from a data container. 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | readonly BACKUP_DIR=${ROOT_DIR}/${BACKUP_DIRECTORY} 20 | readonly RESTORE_CONTAINER="rst_from_volume" 21 | 22 | # Helper functions 23 | err() { 24 | printf '%b\n' "" 25 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 26 | printf '%b\n' "" 27 | exit 1 28 | } >&2 29 | 30 | success() { 31 | printf '%b\n' "" 32 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 33 | printf '%b\n' "" 34 | } 35 | 36 | usage() { 37 | printf '%b\n' "" 38 | printf '%b\n' "No backup archive provided." 39 | printf '%b\n' "Usage: restore.sh {path-to-backup-archive.tar}" 40 | printf '%b\n' "" 41 | exit 1 42 | } 43 | 44 | checkRunningRestore() { 45 | printf '%b\n' ":: Searching for running restore container..." 46 | CONTAINER_SEARCH=$(docker ps -q --filter="name="$RESTORE_CONTAINER"") 47 | 48 | if [ ! -z "$CONTAINER_SEARCH" ]; then 49 | printf '%b\n' " container is found" 50 | err "restore is already running" 51 | fi 52 | } 53 | 54 | cleaningBusybox() { 55 | printf '%b\n' ":: Searching for restore container..." 56 | CONTAINER_SEARCH=$(docker ps -aq --filter="name="$RESTORE_CONTAINER"") 57 | 58 | if [ ! -z "$CONTAINER_SEARCH" ]; then 59 | printf '%b\n' " restore container found" 60 | printf '%b\n' " cleaning container" 61 | # remove container 62 | docker rm ${RESTORE_CONTAINER} 63 | fi 64 | } 65 | 66 | #------------------ 67 | # SCRIPT ENTRYPOINT 68 | #------------------ 69 | if [ $# == 0 ]; then 70 | usage 71 | fi 72 | 73 | printf '%b\n' ":: Searching for backup file..." 74 | if [ ! -f $1 ]; then 75 | err "Backup archive '$1' is not found" 76 | fi 77 | backup_file=$1 78 | printf '%b\n' " backup archive exists" 79 | printf '%b\n' "" 80 | 81 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" container" 82 | CONTAINER_ID=$(docker ps -aq --filter="name="$CONTAINER_NAME"") 83 | if [ -z "$CONTAINER_ID" ]; then 84 | err ""$CONTAINER_NAME" container not found" 85 | fi 86 | printf '%b\n' " container found" 87 | printf '%b\n' "" 88 | printf '%b\n' ":: Restoring /"$CONTAINER_NAME" folder into container..." 89 | 90 | checkRunningRestore 91 | 92 | cleaningBusybox 93 | 94 | printf '%b\n' ":: Starting restore..." 95 | 96 | $(docker run --name=""$RESTORE_CONTAINER"" --rm --volumes-from ${CONTAINER_NAME} -v $(pwd)/${backup_file}:/backup.tar busybox tar xf /backup.tar) 97 | if [[ "$?" -ne 0 ]]; then 98 | err "Could not restore backup into "$CONTAINER_NAME" container" 99 | fi 100 | 101 | printf '%b\n' " backup imported into "$CONTAINER_NAME" container" 102 | 103 | cleaningBusybox 104 | 105 | success "Restoring of backups complete successfull." 106 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | # Every Vagrant development environment requires a box. You can search for 14 | # boxes at https://atlas.hashicorp.com/search. 15 | config.vm.box = "blacklabelops/latestdockerdev" 16 | config.vm.box_url = "https://atlas.hashicorp.com/blacklabelops/boxes/dockerdev/versions/1.latest/providers/virtualbox.box" 17 | 18 | 19 | # Disable automatic box update checking. If you disable this, then 20 | # boxes will only be checked for updates when the user runs 21 | # `vagrant box outdated`. This is not recommended. 22 | # config.vm.box_check_update = false 23 | 24 | # Create a forwarded port mapping which allows access to a specific port 25 | # within the machine from a port on the host machine. In the example below, 26 | # accessing "localhost:8080" will access port 80 on the guest machine. 27 | config.vm.network "forwarded_port", guest: 8080, host: 9200 28 | 29 | # Create a private network, which allows host-only access to the machine 30 | # using a specific IP. 31 | # config.vm.network "private_network", ip: "192.168.33.10" 32 | 33 | # Create a public network, which generally matched to bridged network. 34 | # Bridged networks make the machine appear as another physical device on 35 | # your network. 36 | # config.vm.network "public_network" 37 | 38 | # Share an additional folder to the guest VM. The first argument is 39 | # the path on the host to the actual folder. The second argument is 40 | # the path on the guest to mount the folder. And the optional third 41 | # argument is a set of non-required options. 42 | # config.vm.synced_folder "../data", "/vagrant_data" 43 | 44 | # Provider-specific configuration so you can fine-tune various 45 | # backing providers for Vagrant. These expose provider-specific options. 46 | # Example for VirtualBox: 47 | # 48 | # config.vm.provider "virtualbox" do |vb| 49 | # # Display the VirtualBox GUI when booting the machine 50 | # vb.gui = true 51 | # 52 | # # Customize the amount of memory on the VM: 53 | # vb.memory = "1024" 54 | # end 55 | # 56 | # View the documentation for the provider you are using for more 57 | # information on available options. 58 | 59 | # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies 60 | # such as FTP and Heroku are also available. See the documentation at 61 | # https://docs.vagrantup.com/v2/push/atlas.html for more information. 62 | # config.push.define "atlas" do |push| 63 | # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" 64 | # end 65 | 66 | # Enable provisioning with a shell script. Additional provisioners such as 67 | # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the 68 | # documentation for more information about their specific syntax and use. 69 | # config.vm.provision "shell", inline: <<-SHELL 70 | # sudo apt-get update 71 | # sudo apt-get install -y apache2 72 | # SHELL 73 | end 74 | -------------------------------------------------------------------------------- /scripts/backupCold.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Backup docker volume ["/jenkins"] from docker container. 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | readonly BACKUP_DIR=${ROOT_DIR}/${BACKUP_DIRECTORY} 20 | readonly BACKUP_CONTAINER="bckp_for_volume" 21 | 22 | # Helper functions 23 | err() { 24 | printf '%b\n' "" 25 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 26 | printf '%b\n' "" 27 | exit 1 28 | } >&2 29 | 30 | success() { 31 | printf '%b\n' "" 32 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 33 | printf '%b\n' "" 34 | } 35 | 36 | checkRunningBackup() { 37 | printf '%b\n' ":: Searching for running backup container..." 38 | CONTAINER_SEARCH=$(docker ps -q --filter="name="$BACKUP_CONTAINER"") 39 | 40 | if [ ! -z "$CONTAINER_SEARCH" ]; then 41 | printf '%b\n' " container is found" 42 | err "backup is already running" 43 | fi 44 | } 45 | 46 | cleaningBusybox() { 47 | printf '%b\n' ":: Searching for backup container..." 48 | CONTAINER_SEARCH=$(docker ps -aq --filter="name="$BACKUP_CONTAINER"") 49 | 50 | if [ ! -z "$CONTAINER_SEARCH" ]; then 51 | printf '%b\n' " backup container found" 52 | printf '%b\n' " cleaning container" 53 | # remove container 54 | docker rm ${BACKUP_CONTAINER} 55 | fi 56 | } 57 | 58 | #------------------ 59 | # SCRIPT ENTRYPOINT 60 | #------------------ 61 | 62 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" docker container..." 63 | CONTAINER_ID=$(docker ps -aq --filter="name="$CONTAINER_NAME"") 64 | 65 | if [ -z "$CONTAINER_ID" ]; then 66 | err ""$CONTAINER_NAME" container not found" 67 | fi 68 | 69 | printf '%b\n' " container found" 70 | printf '%b\n' "" 71 | printf '%b\n' ":: Backuping "$CONTAINER_VOLUME" folder from container..." 72 | 73 | # make sure backups directory exists 74 | if [ ! -d "${BACKUP_DIR}" ]; then 75 | err ""$BACKUP_DIR" not found" 76 | fi 77 | 78 | checkRunningBackup 79 | 80 | cleaningBusybox 81 | 82 | printf '%b\n' ":: Starting backup..." 83 | 84 | # stop jenkins, because we cannot import in running container 85 | printf '%b\n' " stop container if running" 86 | stopped=$(docker stop ${CONTAINER_NAME}) 87 | if [[ "$?" -ne 0 ]]; then 88 | err "Could not stop "$CONTAINER_NAME" container" 89 | fi 90 | 91 | backup_filename=${BACKUP_FILE_PREFIX}-$(date +$FILE_TIMESTAMP).tar 92 | $(docker run --name=""$BACKUP_CONTAINER"" --rm --volumes-from ${CONTAINER_NAME} -v ${BACKUP_DIR}:/backup busybox tar cf /backup/${backup_filename} ${CONTAINER_VOLUME}) 93 | if [[ "$?" -ne 0 ]]; then 94 | err "Backup failed" 95 | fi 96 | 97 | cleaningBusybox 98 | 99 | printf '%b\n' ":: Starting "$CONTAINER_NAME" with again..." 100 | running=$(docker start ${CONTAINER_NAME}) 101 | if [[ "$?" -ne 0 ]]; then 102 | err "Could not start stopped "$CONTAINER_NAME" container" 103 | fi 104 | 105 | printf '%b\n' " backup directory: ${BACKUP_DIR}" 106 | printf '%b\n' " backup file : ${backup_filename}" 107 | 108 | success "Backup complete" 109 | -------------------------------------------------------------------------------- /getting_jenkins_docker_ready.md: -------------------------------------------------------------------------------- 1 | # Getting Jenkins Cloud Ready 2 | 3 | Jenkins is a continuous integration tool for software development. You can define jobs, integration and deployment and schedule their execution. It's one of the most important tools in software development. The developer does not have to wait for a feedback but will be informed with detailed infos on how his new feature has fared inside the environments. 4 | 5 | Jenkins tend to get bulky in time. Projects have to set up their unique demands, e.g. software versions and installations (Java 6-8, Tomcat, JBoss, Websphere). As a result, a master-slave setup can ease the complexity of setting up Jenkins but setting up the master-slave environment itself remains. 6 | 7 | The perfect solution is the cloud where you can setup any complex environment with containers and setup templates. Especially the Google Compute Engine looks interesting as you pay for use and you do not have any setup costs. 8 | 9 | Therefore, I aim to define a setup template for cloud deployment and then explode my setup into the cloud. Which means setting up a secure Jenkins master with a scalable amount of build slaves. This will enable teams to setup a build environment per project rather than per team or company. The setup can be deployed and removed on demand and enable indefinite staging environments for software development. 10 | 11 | The first step is building the appropriate cloud container using Docker. Docker is a container framework where you setup applications inside a linux container and being able to fire it up in any cloud environment. Jenkins is by its history an on-premise solution and setup is usually done by hand. A Jenkins instance is not by default able for deploy-and-use inside the cloud. Appropriate means: 12 | 13 | * The container must include a ready-to-use Jenkins. 14 | * The container must have a default security setup. 15 | * The container must accept slave connections. 16 | * The container must support backup & restore. 17 | 18 | In my Github repository and project [blacklabelops/jenkins](https://github.com/blacklabelops/jenkins) I implemented a cloud-ready Jenkins master inside a Docker container. The project has elaborate documentation, feel free to roam and try it out. Managing Jenkins inside Docker required the following steps: 19 | 20 | 1. Setting up a Dockerfile that installs Jenkins, Java and required software packages. 21 | 1. Extending the Dockerfile by configuring Jenkins to use my pre-defined Docker Volume for persisting its settings and using it as the default workfolder. 22 | 1. As a result I could write bash scripts in order to backup & restore the Docker Volume. Now I was able to resume my immutable container in any state. 23 | 1. Define environment variables to be able to configure my container for specific use cases. Being able to control security setup, ports for slave connection and plugin installations. 24 | 1. Environment variables are interpreted at startup and they use the docker-entrypoint script for applying their intend. The script itself is hooked inside the Dockerfile. 25 | 1. Implementing several Groovy Scripts to execute the settings inside Jenkins, e.g. settings for security and the java virtual machine. Blacklabelops Groovy Scripts. 26 | 27 | The container is build and deployed by the public Docker registry Docker Hub and checked by Continuous Integration by Circle-CI. Docker Hub and Circle-CI are free for public Github Repositories. You can always check my repository for the current state of my project as build badges provide a good overview of my implementation state. 28 | 29 | -------------------------------------------------------------------------------- /scripts/restoreConfiguration.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Restore jenkins configuration from a backup archive. 4 | # 5 | 6 | set -o pipefail # return the exit status of the last command in the pipe 7 | set -o nounset # treat unset variables and parameters as an error 8 | 9 | # Setting environment variables 10 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 11 | 12 | printf '%b\n' ":: Reading scrips config...." 13 | source $CUR_DIR/scripts.cfg 14 | 15 | printf '%b\n' ":: Reading container config...." 16 | source $CUR_DIR/container.cfg 17 | 18 | readonly BACKUP_DIR=${ROOT_DIR}/${BACKUP_DIRECTORY} 19 | readonly RESTORE_CONTAINER="rst_from_volume" 20 | 21 | # Helper functions 22 | err() { 23 | printf '%b\n' "" 24 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 25 | printf '%b\n' "" 26 | exit 1 27 | } >&2 28 | 29 | success() { 30 | printf '%b\n' "" 31 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 32 | printf '%b\n' "" 33 | } 34 | 35 | usage() { 36 | printf '%b\n' "" 37 | printf '%b\n' "No backup archive provided." 38 | printf '%b\n' "Usage: restore.sh {path-to-backup-archive.tar}" 39 | printf '%b\n' "" 40 | exit 1 41 | } 42 | 43 | checkRunningRestore() { 44 | printf '%b\n' ":: Searching for running restore container..." 45 | CONTAINER_SEARCH=$(docker ps -q --filter="name="$RESTORE_CONTAINER"") 46 | 47 | if [ ! -z "$CONTAINER_SEARCH" ]; then 48 | printf '%b\n' " container is found" 49 | err "restore is already running" 50 | fi 51 | } 52 | 53 | cleaningBusybox() { 54 | printf '%b\n' ":: Searching for restore container..." 55 | CONTAINER_SEARCH=$(docker ps -aq --filter="name="$RESTORE_CONTAINER"") 56 | 57 | if [ ! -z "$CONTAINER_SEARCH" ]; then 58 | printf '%b\n' " restore container found" 59 | printf '%b\n' " cleaning container" 60 | # remove container 61 | docker rm ${RESTORE_CONTAINER} 62 | fi 63 | } 64 | 65 | #------------------ 66 | # SCRIPT ENTRYPOINT 67 | #------------------ 68 | if [ $# == 0 ]; then 69 | usage 70 | fi 71 | 72 | printf '%b\n' ":: Searching for backup file..." 73 | if [ ! -f $1 ]; then 74 | err "Backup archive '$1' is not found" 75 | fi 76 | backup_file=$1 77 | printf '%b\n' " backup archive exists" 78 | printf '%b\n' "" 79 | 80 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" container" 81 | CONTAINER_ID=$(docker ps -aq --filter="name="$CONTAINER_NAME"") 82 | if [ -z "$CONTAINER_ID" ]; then 83 | err ""$CONTAINER_NAME" container not found" 84 | fi 85 | printf '%b\n' " container found" 86 | printf '%b\n' "" 87 | printf '%b\n' ":: Restoring /"$CONTAINER_NAME" folder into container..." 88 | 89 | # stop jenkins, because we cannot import in running container 90 | printf '%b\n' " stop container if running" 91 | stopped=$(docker stop ${CONTAINER_NAME}) 92 | if [[ "$?" -ne 0 ]]; then 93 | err "Could not stop "$CONTAINER_NAME" container" 94 | fi 95 | 96 | checkRunningRestore 97 | 98 | cleaningBusybox 99 | 100 | printf '%b\n' ":: Starting restore..." 101 | 102 | docker run --name=""$RESTORE_CONTAINER"" --rm --volumes-from ${CONTAINER_NAME} -v $(pwd)/${backup_file}:/backup.tar busybox tar xf /backup.tar jenkins/jobs jenkins/userContent jenkins/fingerprints jenkins/plugins jenkins/secrets jenkins/users jenkins/logs jenkins/secret.* jenkins/*.xml 103 | 104 | printf '%b\n' " backup imported into "$CONTAINER_NAME" container" 105 | printf '%b\n' "" 106 | printf '%b\n' ":: Starting "$CONTAINER_NAME" with restored data again..." 107 | running=$(docker start ${CONTAINER_NAME}) 108 | if [[ "$?" -ne 0 ]]; then 109 | err "Could not start stopped "$CONTAINER_NAME" container" 110 | fi 111 | 112 | cleaningBusybox 113 | 114 | success "Restoring of backups complete successfull." 115 | -------------------------------------------------------------------------------- /scripts/restore.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Restore docker volume from a data container. 4 | # 5 | 6 | set -o errexit # abort script at first error 7 | set -o pipefail # return the exit status of the last command in the pipe 8 | set -o nounset # treat unset variables and parameters as an error 9 | 10 | # Setting environment variables 11 | readonly CUR_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) 12 | 13 | printf '%b\n' ":: Reading scrips config...." 14 | source $CUR_DIR/scripts.cfg 15 | 16 | printf '%b\n' ":: Reading container config...." 17 | source $CUR_DIR/container.cfg 18 | 19 | readonly BACKUP_DIR=${ROOT_DIR}/${BACKUP_DIRECTORY} 20 | readonly RESTORE_CONTAINER="rst_from_volume" 21 | 22 | # Helper functions 23 | err() { 24 | printf '%b\n' "" 25 | printf '%b\n' "\033[1;31m[ERROR] $@\033[0m" 26 | printf '%b\n' "" 27 | exit 1 28 | } >&2 29 | 30 | success() { 31 | printf '%b\n' "" 32 | printf '%b\n' "\033[1;32m[SUCCESS] $@\033[0m" 33 | printf '%b\n' "" 34 | } 35 | 36 | usage() { 37 | printf '%b\n' "" 38 | printf '%b\n' "No backup archive provided." 39 | printf '%b\n' "Usage: restore.sh {path-to-backup-archive.tar}" 40 | printf '%b\n' "" 41 | exit 1 42 | } 43 | 44 | checkRunningRestore() { 45 | printf '%b\n' ":: Searching for running restore container..." 46 | CONTAINER_SEARCH=$(docker ps -q --filter="name="$RESTORE_CONTAINER"") 47 | 48 | if [ ! -z "$CONTAINER_SEARCH" ]; then 49 | printf '%b\n' " container is found" 50 | err "restore is already running" 51 | fi 52 | } 53 | 54 | cleaningBusybox() { 55 | printf '%b\n' ":: Searching for restore container..." 56 | CONTAINER_SEARCH=$(docker ps -aq --filter="name="$RESTORE_CONTAINER"") 57 | 58 | if [ ! -z "$CONTAINER_SEARCH" ]; then 59 | printf '%b\n' " restore container found" 60 | printf '%b\n' " cleaning container" 61 | # remove container 62 | docker rm ${RESTORE_CONTAINER} 63 | fi 64 | } 65 | 66 | #------------------ 67 | # SCRIPT ENTRYPOINT 68 | #------------------ 69 | if [ $# == 0 ]; then 70 | usage 71 | fi 72 | 73 | printf '%b\n' ":: Searching for backup file..." 74 | if [ ! -f $1 ]; then 75 | err "Backup archive '$1' is not found" 76 | fi 77 | backup_file=$1 78 | printf '%b\n' " backup archive exists" 79 | printf '%b\n' "" 80 | 81 | printf '%b\n' ":: Searching for "$CONTAINER_NAME" container" 82 | CONTAINER_ID=$(docker ps -aq --filter="name="$CONTAINER_NAME"") 83 | if [ -z "$CONTAINER_ID" ]; then 84 | err ""$CONTAINER_NAME" container not found" 85 | fi 86 | printf '%b\n' " container found" 87 | printf '%b\n' "" 88 | printf '%b\n' ":: Restoring /"$CONTAINER_NAME" folder into container..." 89 | 90 | # stop jenkins, because we cannot import in running container 91 | printf '%b\n' " stop container if running" 92 | stopped=$(docker stop ${CONTAINER_NAME}) 93 | if [[ "$?" -ne 0 ]]; then 94 | err "Could not stop "$CONTAINER_NAME" container" 95 | fi 96 | 97 | checkRunningRestore 98 | 99 | cleaningBusybox 100 | 101 | printf '%b\n' ":: Starting restore..." 102 | 103 | $(docker run --name=""$RESTORE_CONTAINER"" --rm --volumes-from ${CONTAINER_NAME} -v $(pwd)/${backup_file}:/backup.tar busybox tar xf /backup.tar) 104 | if [[ "$?" -ne 0 ]]; then 105 | err "Could not restore backup into "$CONTAINER_NAME" container" 106 | fi 107 | 108 | printf '%b\n' " backup imported into "$CONTAINER_NAME" container" 109 | printf '%b\n' "" 110 | printf '%b\n' ":: Starting "$CONTAINER_NAME" with restored data again..." 111 | running=$(docker start ${CONTAINER_NAME}) 112 | if [[ "$?" -ne 0 ]]; then 113 | err "Could not start stopped "$CONTAINER_NAME" container" 114 | fi 115 | 116 | cleaningBusybox 117 | 118 | success "Restoring of backups complete successfull." 119 | 120 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM blacklabelops/java:server-jre.8 2 | 3 | # Build time arguments 4 | # Values: latest or version number 5 | ARG JENKINS_VERSION=latest 6 | ARG JENKINS_HASH= 7 | # Cli installation details 8 | ARG JENKINS_CLI_VERSION=2.121.3 9 | ARG JENKINS_CLI_HASH= 10 | # Values: war or war-stable 11 | ARG JENKINS_RELEASE=war 12 | # Permissions, set the linux user id and group id 13 | ARG CONTAINER_UID=1000 14 | ARG CONTAINER_GID=1000 15 | 16 | # Container Environment Variables 17 | ENV JENKINS_HOME=/jenkins 18 | 19 | RUN export CONTAINER_USER=jenkins && \ 20 | export CONTAINER_GROUP=jenkins && \ 21 | # Add User 22 | addgroup -g $CONTAINER_GID jenkins && \ 23 | adduser -u $CONTAINER_UID -G jenkins -h /home/jenkins -s /bin/bash -S jenkins && \ 24 | # Install Software 25 | apk add --update \ 26 | git \ 27 | wget && \ 28 | # Install Jenkins 29 | mkdir -p /usr/bin/jenkins && \ 30 | wget --directory-prefix=/usr/bin/jenkins \ 31 | http://mirrors.jenkins-ci.org/${JENKINS_RELEASE}/${JENKINS_VERSION}/jenkins.war && \ 32 | JENKINS_HASH=$(sha1sum /usr/bin/jenkins/jenkins.war) && \ 33 | echo 'Calculated checksum: '$JENKINS_HASH && \ 34 | touch /usr/bin/jenkins-cli && \ 35 | touch /usr/bin/cli && \ 36 | # Install Jenkins cli 37 | wget --directory-prefix=/usr/bin/jenkins \ 38 | http://repo.jenkins-ci.org/public/org/jenkins-ci/main/cli/${JENKINS_CLI_VERSION}/cli-${JENKINS_CLI_VERSION}-jar-with-dependencies.jar && \ 39 | mv /usr/bin/jenkins/cli-${JENKINS_CLI_VERSION}-jar-with-dependencies.jar /usr/bin/jenkins/cli.jar && \ 40 | JENKINS_CLI_HASH=$(sha1sum /usr/bin/jenkins/cli.jar) && \ 41 | echo 'Calculated checksum: '$JENKINS_CLI_HASH && \ 42 | # Jenkins permissions 43 | chown -R $CONTAINER_USER:$CONTAINER_GROUP /usr/bin/jenkins /usr/bin/jenkins-cli /usr/bin/cli && \ 44 | chmod ug+x /usr/bin/jenkins/jenkins.war /usr/bin/jenkins/cli.jar /usr/bin/jenkins-cli /usr/bin/cli && \ 45 | # Jenkins directory 46 | mkdir -p ${JENKINS_HOME} && \ 47 | chown -R $CONTAINER_USER:$CONTAINER_GROUP ${JENKINS_HOME} && \ 48 | # Adding letsencrypt-ca to truststore 49 | export KEYSTORE=$JAVA_HOME/jre/lib/security/cacerts && \ 50 | wget -P /tmp/ https://letsencrypt.org/certs/letsencryptauthorityx1.der && \ 51 | wget -P /tmp/ https://letsencrypt.org/certs/letsencryptauthorityx2.der && \ 52 | wget -P /tmp/ https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.der && \ 53 | wget -P /tmp/ https://letsencrypt.org/certs/lets-encrypt-x2-cross-signed.der && \ 54 | wget -P /tmp/ https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.der && \ 55 | wget -P /tmp/ https://letsencrypt.org/certs/lets-encrypt-x4-cross-signed.der && \ 56 | keytool -trustcacerts -keystore $KEYSTORE -storepass changeit -noprompt -importcert -alias isrgrootx1 -file /tmp/letsencryptauthorityx1.der && \ 57 | keytool -trustcacerts -keystore $KEYSTORE -storepass changeit -noprompt -importcert -alias isrgrootx2 -file /tmp/letsencryptauthorityx2.der && \ 58 | keytool -trustcacerts -keystore $KEYSTORE -storepass changeit -noprompt -importcert -alias letsencryptauthorityx1 -file /tmp/lets-encrypt-x1-cross-signed.der && \ 59 | keytool -trustcacerts -keystore $KEYSTORE -storepass changeit -noprompt -importcert -alias letsencryptauthorityx2 -file /tmp/lets-encrypt-x2-cross-signed.der && \ 60 | keytool -trustcacerts -keystore $KEYSTORE -storepass changeit -noprompt -importcert -alias letsencryptauthorityx3 -file /tmp/lets-encrypt-x3-cross-signed.der && \ 61 | keytool -trustcacerts -keystore $KEYSTORE -storepass changeit -noprompt -importcert -alias letsencryptauthorityx4 -file /tmp/lets-encrypt-x4-cross-signed.der && \ 62 | # Remove obsolete packages and cleanup 63 | apk del wget && \ 64 | rm -rf /var/cache/apk/* && rm -rf /var/log/* && rm -rf /tmp/* 65 | 66 | LABEL com.blacklabelops.application.jenkins.version=$JENKINS_VERSION-$JENKINS_RELEASE \ 67 | com.blacklabelops.application.jenkins.hash=$JENKINS_HASH \ 68 | com.blacklabelops.application.jenkins.hashtype=sha1sum \ 69 | com.blacklabelops.application.jenkins.userid=$CONTAINER_UID \ 70 | com.blacklabelops.application.jenkins.groupid=$CONTAINER_GID \ 71 | com.blacklabelops.application.jenkinscli.version=$JENKINS_CLI_VERSION \ 72 | com.blacklabelops.application.jenkinscli.hash=$JENKINS_CLI_HASH \ 73 | com.blacklabelops.application.jenkinscli.hashtype=sha1sum 74 | 75 | # Entrypoint Environment Variables 76 | ENV JAVA_VM_PARAMETERS=-Xmx512m \ 77 | JENKINS_PRODUCTION_SETTINGS=false \ 78 | JENKINS_MASTER_EXECUTORS= \ 79 | JENKINS_SLAVEPORT=50000 \ 80 | JENKINS_PLUGINS= \ 81 | JENKINS_PARAMETERS= \ 82 | JENKINS_KEYSTORE_PASSWORD= \ 83 | JENKINS_CERTIFICATE_DNAME= \ 84 | JENKINS_ENV_FILE= \ 85 | JENKINS_DELAYED_START= \ 86 | JENKINS_CLI_URL=http://localhost:8080 \ 87 | JENKINS_CLI_SSH= 88 | 89 | WORKDIR ${JENKINS_HOME} 90 | VOLUME ["${JENKINS_HOME}"] 91 | EXPOSE 8080 50000 92 | 93 | USER jenkins 94 | COPY imagescripts/ /home/jenkins 95 | ENTRYPOINT ["/sbin/tini","--","/home/jenkins/docker-entrypoint.sh"] 96 | CMD ["jenkins"] 97 | -------------------------------------------------------------------------------- /gitbook/manual/env_variables.md: -------------------------------------------------------------------------------- 1 | # Environment Variables 2 | 3 | The following setting can be configured by using Docker environment variables. 4 | 5 | ## Jenkins HTTPS 6 | 7 | This container can create ad-hoc self-signed certificates for https without any reverse proxy. This 8 | gives some out of the box network security. Note that reverse proxies and proper certificate work flows are always 9 | to be prefered! I will use this until the Google Cloud Engine https load balancer will work. 10 | 11 | At startup the container will create a unique self-signed certificate. This certificat will live as long as the docker volume. You have to pass Distinguished Name (DN) and a keystore password. The certificate is generated by a Distinguished Name and secured by the keystore password. This is a DN-Example: 12 | 13 | ~~~~ 14 | CN=SBleul,OU=Blacklabelops,O=blacklabelops.net,L=Munich,S=Bavaria,C=DE 15 | ~~~~ 16 | 17 | * CN = Your name 18 | * OU = Your organizational unit. 19 | * O = Organisation name. 20 | * L = Location, e.g. town name. 21 | * S = State 22 | * C = Locale of your county. 23 | 24 | Now start your container with additional parameters for starting jenkins with https and a keystore password. 25 | 26 | ~~~~ 27 | $ docker run --name jenkins \ 28 | -e "JENKINS_KEYSTORE_PASSWORD=swordfish" \ 29 | -e "JENKINS_CERTIFICATE_DNAME=CN=SBleul,OU=Blacklabelops,O=blacklabelops.net,L=Munich,S=Bavaria,C=DE" \ 30 | -p 443:8080 \ 31 | blacklabelops/jenkins 32 | ~~~~ 33 | 34 | > Congratulations! You can now access your jenkins instance with simply typing https://youinstance.com! Accept the certificate inside your browser and have fun! 35 | 36 | ## Jenkins Security 37 | 38 | This container support matrix enabled user security and admin account at startup. Jenkins 39 | will be locked up and only allows the defined admin user. Afterwards users and rights 40 | can be configured as usual. The admin password can be changed any time. I use this for starting 41 | the container up inside cloud environments. 42 | 43 | ~~~~ 44 | $ docker run -d --name jenkins \ 45 | -e "JENKINS_ADMIN_USER=jenkins" \ 46 | -e "JENKINS_ADMIN_PASSWORD=swordfish" \ 47 | -p 8090:8080 \ 48 | blacklabelops/jenkins 49 | ~~~~ 50 | 51 | ## Jenkins Installing Plugins 52 | 53 | Finally got this working: 54 | 55 | You can define a set of plugins that will be installed, if necessary, during initialization. Very good 56 | for testing out new plugins. Also adding default plugins like swarm. You have to define a list 57 | of plugin-ids seperated by a whitespace. 58 | 59 | ~~~~ 60 | $ docker run --name jenkins \ 61 | -e "JENKINS_PLUGINS=gitlab-plugin hipchat swarm" \ 62 | -p 8090:8080 \ 63 | blacklabelops/jenkins 64 | ~~~~ 65 | 66 | > This will install the plugins gitlab-plugin hipchat swarm once during post-inistialization. 67 | 68 | ## Jenkins Master Number of Executors 69 | 70 | Jenkins jobs should be executed on slaves therefore it's good to be able to limit 71 | the executors on the master. 72 | 73 | ~~~~ 74 | $ docker run --name jenkins \ 75 | -e "JENKINS_MASTER_EXECUTORS=0" \ 76 | -p 8090:8080 \ 77 | blacklabelops/jenkins 78 | ~~~~ 79 | 80 | ## Jenkins Administrator Address 81 | 82 | > Feature has been removed in version 2.0! 83 | 84 | ## Jenkins Mail SMTP 85 | 86 | The following parameters enable the servers mail settings. 87 | 88 | Minimum example: 89 | 90 | ~~~~ 91 | $ docker run --name jenkins \ 92 | -e "SMTP_USER_NAME=jenkins" \ 93 | -e "SMTP_USER_PASS=swordfish" \ 94 | -e "SMTP_HOST=smtp.mailservice.com" \ 95 | -e "SMTP_PORT=2525" \ 96 | -p 8090:8080 \ 97 | -p 50000:50000 \ 98 | blacklabelops/jenkins 99 | ~~~~ 100 | 101 | Full example: 102 | 103 | ~~~~ 104 | $ docker run --name jenkins \ 105 | -e "SMTP_USER_NAME=jenkins" \ 106 | -e "SMTP_USER_PASS=swordfish" \ 107 | -e "SMTP_HOST=smtp.mailservice.com" \ 108 | -e "SMTP_PORT=2525" \ 109 | -e "SMTP_REPLYTO_ADDRESS=dummy@example.com" \ 110 | -e "SMTP_USE_SSL=true" \ 111 | -e "SMTP_CHARSET=UTF-8" \ 112 | -p 8090:8080 \ 113 | -p 50000:50000 \ 114 | blacklabelops/jenkins 115 | ~~~~ 116 | 117 | ## Jenkins Slave Port 118 | 119 | The slave port enables the automatic connection of jenkins slaves. The port can be configured as follows. 120 | 121 | ~~~~ 122 | $ docker run --name jenkins \ 123 | -e "JENKINS_SLAVEPORT=50000" \ 124 | -p 8090:8080 \ 125 | -p 50000:50000 \ 126 | blacklabelops/jenkins 127 | ~~~~ 128 | 129 | > Slaves can connect on port 50000. 130 | 131 | ## Jenkins Command Line Parameters 132 | 133 | You can define command line parameters. The list of parameters can be found [here](https://wiki.jenkins-ci.org/display/JENKINS/Starting+and+Accessing+Jenkins). 134 | 135 | ~~~~ 136 | docker run -d --name jenkins \ 137 | -e "JENKINS_PARAMETERS=--httpPort=8090" \ 138 | -p 8090:8090 \ 139 | blacklabelops/jenkins 140 | ~~~~ 141 | 142 | > Starts Jenkins with internal port 8090 rather default port 8080. 143 | 144 | ## Java-VM Parameters 145 | 146 | You can define start up parameters for the Java Virtual Machine, e.g. setting the memory size. 147 | 148 | ~~~~ 149 | docker run -d --name jenkins \ 150 | -e "JAVA_VM_PARAMETERS=-Xmx512m -Xms256m" \ 151 | -p 8090:8080 \ 152 | blacklabelops/jenkins 153 | ~~~~ 154 | 155 | > You will have to use Java 8 parameters. 156 | -------------------------------------------------------------------------------- /gitbook/manual/use_bash_scripts.md: -------------------------------------------------------------------------------- 1 | # Using Bash Scripts 2 | 3 | This container includes all the required scripts for container management. Simply clone the project and enter the described commands in your project directory. 4 | 5 | ## Run Recommended 6 | 7 | ~~~~ 8 | $ ./scripts/run.sh 9 | ~~~~ 10 | 11 | > This will run the container with the configuration scripts/container.cfg 12 | 13 | ## Run Docker-Composite 14 | 15 | ~~~~ 16 | $ docker-compose up -d 17 | ~~~~ 18 | 19 | > This will run the container detached with the configuration docker-composite.yml 20 | 21 | ## Run Command Line 22 | 23 | ~~~~ 24 | $ docker run -d -p 8090:8080 --name="jenkins" blacklabelops/jenkins 25 | ~~~~ 26 | 27 | > This will run the jenkins on default settings and port 8090 28 | 29 | ## Build Recommended 30 | 31 | ~~~~ 32 | $ ./scripts/build.sh 33 | ~~~~ 34 | 35 | > This will build the container from scratch with all required parameters. 36 | 37 | ## Build Docker-Composite 38 | 39 | ~~~~ 40 | docker-compose build 41 | ~~~~ 42 | 43 | > This will build the container according to the docker-composite.yml file. 44 | 45 | ## Build Docker Command Line 46 | 47 | ~~~~ 48 | docker build -t="blacklabelops/jenkins" . 49 | ~~~~ 50 | 51 | > This will build the container from scratch. 52 | 53 | ## Docker Wrapper Scripts 54 | 55 | Convenient wrapper scripts for container and image management. The scripts manage one container. In oder to manage multiple containers, copy the scripts and adjust the container.cfg. 56 | 57 | Name | Description 58 | ----------------- | ------------ 59 | build.sh | Build the container from scratch. 60 | run.sh | Run the container. 61 | start.sh | Start the container from a stopped state. 62 | stop.sh | Stop the container from a running state. 63 | rm.sh | Kill all running containers and remove it. 64 | rmi.sh | Delete container image. 65 | mng.sh | Manage the docker volume from another container. 66 | 67 | > Simply invoke the commands in the project's folder. 68 | 69 | ## Feature Scripts 70 | 71 | Feature scripts for the container. The scripts manage one container. In oder to manage multiple containers, copy the scripts and adjust the container.cfg. 72 | 73 | Name | Description 74 | ----------------- | ------------ 75 | logs.sh | Downloads a jenkins logs file from container 76 | backup.sh | Backups docker volume ["/jenkins"] from container 77 | restore.sh | Restore the backup into jenkins container 78 | 79 | > The examples are executed from project folder. 80 | 81 | ### logs.sh 82 | 83 | This script will search for configured docker container. If no container 84 | found, an error message will be shown. Otherwise, an jenkins logs will be 85 | copied by default into 'logs' folder with following file name and timestamp. 86 | 87 | ~~~~ 88 | $ ./scripts/logs.sh 89 | ~~~~ 90 | 91 | > The log file with timestamp as name und suffix ".log" can be found in the project's logs folder. 92 | 93 | #### Error example 94 | 95 | ~~~~ 96 | $ ./scripts/logs.sh 97 | :: Searching for jenkins docker container... 98 | 99 | [ERROR] jenkins container is not found 100 | ~~~~ 101 | 102 | #### Success example 103 | 104 | ~~~~ 105 | $ scripts/logs.sh 106 | :: Reading scrips config.... 107 | :: Reading container config.... 108 | :: Searching for jenkins docker container... 109 | container is found 110 | 111 | :: Downloading logs from container... 112 | logs directory: /home/docker/jenkins/logs 113 | log filename : JenkinsLogs-2015-03-08-16-14-01.log 114 | ~~~~ 115 | 116 | ### backup.sh 117 | 118 | Backup of docker volume in a tar archive. 119 | 120 | ~~~~ 121 | $ ./scripts/backup.sh 122 | ~~~~ 123 | 124 | > The backups will be placed in the project's backups folder. 125 | 126 | #### Error example 127 | 128 | ~~~~ 129 | $ scripts/backup.sh 130 | :: Searching for jenkins docker container... 131 | 132 | [ERROR] jenkins container is not found 133 | ~~~~ 134 | 135 | #### Success example 136 | 137 | ~~~~ 138 | $ scripts/backup.sh 139 | :: Reading scrips config.... 140 | :: Reading container config.... 141 | :: Searching for jenkins docker container... 142 | container found 143 | 144 | :: Backuping /jenkins folder from container... 145 | :: Searching for running backup container... 146 | :: Searching for backup container... 147 | :: Starting backup... 148 | tar: removing leading '/' from member names 149 | :: Searching for backup container... 150 | backup directory: /home/docker/jenkins/backups 151 | backup file : JenkinsBackup-2015-03-08-16-28-40.tar 152 | ~~~~ 153 | 154 | ### restore.sh 155 | 156 | Restore container from a tar archive. 157 | 158 | ~~~~ 159 | $ ./scripts/restore.sh ./backups/JenkinsBackup-2015-03-08-16-28-40.tar 160 | ~~~~ 161 | 162 | > A temp container will be created and backup file will be extracted into docker volume. The container will be stopped and restartet afterwards. 163 | 164 | #### Error example 165 | 166 | ~~~~ 167 | $ scripts/restore.sh 168 | 169 | :: Reading scrips config.... 170 | :: Reading container config.... 171 | 172 | No backup archive provided. 173 | Usage: restore.sh {path-to-backup-archive.tar} 174 | ~~~~ 175 | 176 | #### Success example 177 | 178 | ~~~~ 179 | $ ./scripts/restore.sh ./backups/JenkinsBackup-2015-03-08-16-28-40.tar 180 | :: Reading scrips config.... 181 | :: Reading container config.... 182 | :: Searching for backup file... 183 | backup archive exists 184 | 185 | :: Searching for jenkins container 186 | container found 187 | 188 | :: Restoring /jenkins folder into container... 189 | stop container if running 190 | :: Searching for running restore container... 191 | :: Searching for restore container... 192 | :: Starting restore... 193 | backup imported into jenkins container 194 | 195 | :: Starting jenkins with restored data again... 196 | :: Searching for restore container... 197 | 198 | [SUCCESS] Restoring of backups complete successfull. 199 | 200 | ~~~~ 201 | 202 | ## Managing Multiple Containers 203 | 204 | The scripts can be configured for the support of different containers on the same host manchine. Just copy and paste the project and folder and adjust the configuration file scripts/container.cfg 205 | 206 | Name | Description 207 | ----------------- | ------------ 208 | CONTAINER_NAME | The name of the docker container. 209 | IMAGE_NAME | The name of the docker image. 210 | HOST_PORT | The exposed port on the host machine. 211 | BACKUP_DIRECTORY | Change the backup directory. 212 | LOGFILE_DIRECTORY | Change the logs download directory. 213 | FILE_TIMESTAMP | Timestamp format for logs and backups. 214 | 215 | > Note: CONTAINER_VOLUME must not be changed. 216 | 217 | ## Setting the Jenkins Version 218 | 219 | The jenkins version is configured in the Dockerfile. Please consider that backups will only work with the respective jenkins versions. 220 | 221 | Dockerfile: 222 | 223 | ~~~~ 224 | ENV JENKINS_VERSION=latest 225 | ~~~~ 226 | 227 | > This will install the latest jenkins version in each build process. 228 | 229 | Dockerfile: 230 | 231 | ~~~~ 232 | ENV JENKINS_VERSION=1.556 233 | ~~~~ 234 | 235 | > This will install the jenkins version 1.556. 236 | --------------------------------------------------------------------------------