├── .gitignore ├── BLOG.md ├── LICENSE ├── README.md ├── jenkins ├── README.md ├── docker-compose.yml ├── docker-proxy │ └── Dockerfile ├── jenkins-master │ ├── Dockerfile │ ├── initagent.groovy │ ├── jenkins.sh │ ├── jenkinsdefaultsecrets.tar.gz │ ├── jenkinsexport.tar.gz │ ├── jobs │ │ └── BasicEnvTest │ │ │ └── config.xml │ ├── plugins.sh │ └── plugins.txt ├── jenkins-nginx │ ├── Dockerfile │ └── conf │ │ ├── jenkins.conf │ │ └── nginx.conf ├── jenkins-slave │ ├── Dockerfile │ └── files │ │ └── resolv.conf └── makefile ├── jenkinsscripts ├── README.md ├── addDockerPluginTemplate.groovy └── addYATDPluginTemplate.groovy ├── monitoring ├── JenkinsMetrics.json ├── README.md ├── data │ └── Dockerfile ├── docker-compose.yml ├── graphite │ ├── Dockerfile │ └── storage-schemas.conf └── makefile ├── scripts ├── README.md ├── configIncludes.txt ├── getExport.sh ├── getSecrets.sh ├── listPlugins.groovy ├── secretsIncludes.txt └── setSecrets.sh ├── tutorial_01 ├── README.md └── makefile ├── tutorial_02 ├── Dockerfile ├── README.md └── makefile ├── tutorial_03 ├── Dockerfile └── makefile ├── tutorial_04 ├── jenkins-master │ └── Dockerfile ├── jenkins-nginx │ ├── Dockerfile │ └── conf │ │ ├── jenkins.conf │ │ └── nginx.conf └── makefile ├── tutorial_05 ├── docker-compose.yml ├── jenkins-master │ ├── Dockerfile │ └── plugins.txt ├── jenkins-nginx │ ├── Dockerfile │ └── conf │ │ ├── jenkins.conf │ │ └── nginx.conf └── makefile ├── tutorial_06 ├── docker-compose.yml ├── jenkins-master │ ├── Dockerfile │ ├── Dockerfile-Centos7 │ ├── init.groovy │ ├── install-plugins.sh │ ├── jenkins-support │ ├── jenkins.sh │ └── plugins.sh ├── jenkins-nginx │ ├── Dockerfile │ └── conf │ │ ├── jenkins.conf │ │ └── nginx.conf └── makefile └── tutorial_07 ├── README.md ├── docker-compose.yml ├── docker-proxy └── Dockerfile ├── jenkins-master ├── Dockerfile ├── Dockerfile-debian ├── init.groovy ├── install-plugins.sh ├── jenkins-support ├── jenkins.sh ├── plugins.sh └── plugins.txt ├── jenkins-nginx ├── Dockerfile └── conf │ ├── jenkins.conf │ └── nginx.conf ├── jenkins-slave ├── Dockerfile └── files │ └── resolv.conf └── makefile /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pem 3 | jenkinslocation.txt 4 | jenkinssecrets.tar.gz -------------------------------------------------------------------------------- /BLOG.md: -------------------------------------------------------------------------------- 1 | # Jenkins and Docker Tutorial Series 2 | 3 | This repository is provided as a set of functional working examples that follows along with a blog series released by Maxfield Stewart at Riot Games, Each folder contains a self contained set of files that are the end result of each tutorial and are provided as is. 4 | 5 | # Blogs In Order of Appearance 6 | 7 | 1. [Thinking Inside the Container](http://engineering.riotgames.com/news/thinking-inside-container) 8 | 2. [Putting Jenkins into a Docker Container](http://engineering.riotgames.com/news/putting-jenkins-docker-container) 9 | 3. [Docker Jenkins and Data that Persists](http://engineering.riotgames.com/news/docker-jenkins-data-persists) 10 | 4. [Jenkins, Docker, Proxies and Compose](http://engineering.riotgames.com/news/jenkins-docker-proxies-and-compose) 11 | 5. [Taking Control of your Docker Image](http://engineering.riotgames.com/news/taking-control-your-docker-image) 12 | 6. [Building With Jenkins Inside an Ephemeral Docker Container](http://engineering.riotgames.com/news/building-jenkins-inside-ephemeral-docker-container) 13 | 14 | # Instructions For Using this Repository 15 | 16 | Ideally users should follow the blog series for specific directions. That said here's some basic setup instructions you will need before these become viable. 17 | 18 | # Step 1 - Install Docker For Mac/Win 19 | 20 | 1. You’ll need Windows 7 (or later) or Mac OSX Sierra or later. 21 | 2. Go to: https://docs.docker.com/docker-for-mac/ (or https://docs.docker.com/docker-for-windows/) 22 | 3. Download and install Docker for your platform 23 | 4. Follow all setup instructions. 24 | 4. Verify your installation is working by opening a docker terminal window (in windows this step is done by clicking the docker quickstart desktop icon) by running the following steps: 25 | 1. Type: docker images (verify it gives you an empty list back with no errors). 26 | 27 | # Step 2 - Choose your Adventure 28 | 29 | 1. If you want to get started with Jenkins right away, follow the instructions for using the pre-built jenkins setup in this repo here: https://github.com/maxfields2000/dockerjenkins_tutorial/blob/master/jenkins/README.md 30 | 2. If you'd prefer to follow the tutorials in the blog and learn as you go/build it yourself, start here: https://engineering.riotgames.com/news/putting-jenkins-docker-container 31 | 32 | 33 | Good luck, Have Fun! -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quick Start Guide 2 | 3 | You can find a more detailed start up guide [here](https://github.com/maxfields2000/dockerjenkins_tutorial/blob/master/jenkins/README.md) 4 | 5 | This will get you up and running with some basic jobs and default config. 6 | 7 | 1. Make sure you have all the pre-reqs installed (Docker for Mac or Docker for Windows) 8 | 2. Clone this repository to your local drive 9 | 3. `cd jenkins` 10 | 1. `make build` 11 | 2. `make run` (if this is your first time it will ask for your docker host IP) 12 | 4. Point your browser to http://localhost (you can get this by running "docker-machine ip default") 13 | 14 | # ATTENTION: Riot Engineer Blog Readers 15 | 16 | If you're following along with Jenkins Tutorial series that uses Jenkins 1 I've placed a corresponding Markdown file [here](https://github.com/maxfields2000/dockerjenkins_tutorial/blob/master/BLOG.md) 17 | 18 | 19 | # ATTENTION: Docker 1.12/1.13 Users! 20 | 21 | This setup is untested on Docker versions 1.12 or older. You will likely have problems if your Docker version doesn't support "LABELS" or "ARGS". Please upgrade, it's well worth it! 22 | 23 | # Monitoring Basics 24 | 25 | You can find a basic monitoring setup in the `monitoring` folder. Check the [README](https://github.com/maxfields2000/dockerjenkins_tutorial/blob/master/monitoring/README.md) 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /jenkins/README.md: -------------------------------------------------------------------------------- 1 | This setup is based on the tutorial you can find here: 2 | 3 | http://engineering.riotgames.com/news/building-jenkins-inside-ephemeral-docker-container 4 | 5 | There several key changes however that won't match that blog. Namely: 6 | 7 | 1. There are utility scripts available to assist you in the root level /scripts directory, these will export config changes and secrets and have directions for how to re-use those if you want to make lasting changes. (They also double as a cheap backup option) 8 | 9 | # Ephemeral Build Slaves using Jenkins and Docker 10 | 11 | This tutorial contains all the files necessary to create your own local Docker for Mac/Windows or Docker-Toolbox version of a fully ephemeral jenkins environment. Build slaves are designed to be docker containers in this configuration. 12 | 13 | # Quick Start Jenkins 14 | 15 | This will get you upa nd running with some basic jobs and default config. But no credentials. 16 | 17 | 1. Make sure you have all the pre-reqs installed (Docker for Mac or Windows) 18 | 2. Clone this repository to your local drive 19 | 3. Inside the **jenkins** folder of your local clone execute the following two commands: 20 | 1. make build 21 | 2. make run (if this is your first time it will ask for your docker host IP) 22 | 4. Point your browser to http://localhost (you can get this by running "docker-machine ip default") 23 | 5. If using Docker for Windows, enable "Listen on Localhost:2375" 24 | 1. Go to jenkins (http://localhost), go to configure, under the docker cloud change the cloud endpoint from "proxy1:2375" to "localhost:2375") 25 | 26 | # Testing Everything Works 27 | 28 | You should just be able to run the job "BasicEnvTest" which will run a simple pipeline job that spins up the test slave and executes a shell command in it. 29 | 30 | If you think your docker setup isn't working do the following to check: 31 | 32 | 1. Got to http://localhost/configure (the jenkins config page) 33 | 2. Scroll down to "Docker Plugin" configuration (part of the clouds setup) 34 | 3. Find the "Test Connection" button and press it 35 | 4. You should get a text string back with version information. 36 | 37 | If you get an error something is wrong with your local Docker setup. If you're running Docker for Windows see step 5 above and adjust configuration accordingly. 38 | 39 | # Rebuilding 40 | 41 | If you edit your dockerfiles because you want to make changes. You will need to rebuild. 42 | 43 | ## Rebuild without blowing away local data 44 | 45 | 1. make stop 46 | 2. make clean 47 | 3. make build 48 | 4. make run 49 | 50 | ## Rebuild AND blow away local data 51 | 52 | 1. make stop 53 | 2. make clean-data 54 | 3. make build 55 | 4. make run 56 | 57 | # Taking a New Configuration Export 58 | 59 | If you want to capture your local environment as "the template" for development. Do the following: 60 | 61 | 1. go the "scripts" folder (cd scripts) 62 | 2. Run: ./getExport.sh 63 | 3. Clean your current setup (make stop, make clean-data) 64 | 4. Rebuild (make build, make run) 65 | 5. Test. 66 | 6. If everything looks good, push up a commit! 67 | 68 | # Exporting your credentials 69 | 70 | If you're going to be doing a lot of blowing away your data you can export your credentials and secrets and re-import them after each build so you don't ahve to keep editing them 71 | 72 | With your environment still running do: 73 | 74 | 1. cd /scripts 75 | 2. ./getSecrets.sh 76 | 3. Rebuild your environment (and blow away local data per above) 77 | 4. ./setSecrets.sh 78 | 5. make stop 79 | 6. make run 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /jenkins/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | master: 4 | build: ./jenkins-master 5 | ports: 6 | - "50000:50000" 7 | volumes: 8 | - jenkins-log:/var/log/jenkins 9 | - jenkins-data:/var/jenkins_home 10 | networks: 11 | - jenkins-net 12 | nginx: 13 | build: ./jenkins-nginx 14 | ports: 15 | - "80:80" 16 | networks: 17 | - jenkins-net 18 | slave: 19 | build: ./jenkins-slave 20 | proxy: 21 | build: ./docker-proxy 22 | volumes: 23 | - /var/run/docker.sock:/var/run/docker.sock 24 | networks: 25 | jenkins-net: 26 | aliases: 27 | - proxy1 28 | volumes: 29 | jenkins-data: 30 | jenkins-log: 31 | networks: 32 | jenkins-net: 33 | 34 | 35 | -------------------------------------------------------------------------------- /jenkins/docker-proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | RUN yum -y install socat && \ 5 | yum clean all 6 | 7 | VOLUME /var/run/docker.sock 8 | 9 | # docker tcp port 10 | EXPOSE 2375 11 | 12 | ENTRYPOINT ["socat", "TCP-LISTEN:2375,reuseaddr,fork","UNIX-CLIENT:/var/run/docker.sock"] -------------------------------------------------------------------------------- /jenkins/jenkins-master/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Yum workaround to stalled mirror 5 | RUN sed -i -e 's/enabled=1/enabled=0/g' /etc/yum/pluginconf.d/fastestmirror.conf 6 | 7 | RUN rm -f /var/lib/rpm/__* 8 | RUN rpm --rebuilddb -v -v 9 | RUN yum clean all 10 | 11 | 12 | # see https://bugs.debian.org/775775 13 | # and https://github.com/docker-library/java/issues/19#issuecomment-70546872 14 | ENV CA_CERTIFICATES_JAVA_VERSION 20140324 15 | 16 | RUN yum -v install -y \ 17 | wget \ 18 | zip \ 19 | openssh-client \ 20 | unzip \ 21 | java-1.8.0-openjdk \ 22 | git \ 23 | dos2unix \ 24 | && yum clean all 25 | 26 | #RUN /var/lib/dpkg/info/ca-certificates-java.postinst configure 27 | 28 | # Install Tini 29 | ENV TINI_VERSION 0.9.0 30 | ENV TINI_SHA fa23d1e20732501c3bb8eeeca423c89ac80ed452 31 | 32 | # Use tini as subreaper in Docker container to adopt zombie processes 33 | RUN curl -fsSL https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini-static -o /bin/tini && chmod +x /bin/tini \ 34 | && echo "$TINI_SHA /bin/tini" | sha1sum -c - 35 | 36 | # SET Jenkins Environment Variables 37 | ENV JENKINS_HOME /var/jenkins_home 38 | ENV JENKINS_SLAVE_AGENT_PORT 50000 39 | ENV JENKINS_VERSION 2.125 40 | ENV JENKINS_UC https://updates.jenkins-ci.org 41 | ENV COPY_REFERENCE_FILE_LOG $JENKINS_HOME/copy_reference_file.log 42 | 43 | # Jenkins is run with user `jenkins`, uid = 1000 44 | # If you bind mount a volume from the host or a data container, 45 | # ensure you use the same uid 46 | RUN useradd -d "$JENKINS_HOME" -u 1000 -m -s /bin/bash jenkins 47 | 48 | # `/usr/share/jenkins/ref/` contains all reference configuration we want 49 | # to set on a fresh new installation. Use it to bundle additional plugins 50 | # or config file with your custom jenkins Docker image. 51 | RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d 52 | 53 | # Install Jenkins 54 | RUN curl -fL http://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/${JENKINS_VERSION}/jenkins-war-${JENKINS_VERSION}.war -o /usr/share/jenkins/jenkins.war 55 | 56 | ENV JAVA_OPTS="-Xmx8192m" 57 | ENV JENKINS_OPTS="--logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" 58 | 59 | # Prep Jenkins Directories 60 | RUN chown -R jenkins "$JENKINS_HOME" /usr/share/jenkins/ref 61 | RUN mkdir /var/log/jenkins 62 | RUN mkdir /var/cache/jenkins 63 | RUN chown -R jenkins:jenkins /var/log/jenkins 64 | RUN chown -R jenkins:jenkins /var/cache/jenkins 65 | 66 | # Expose Ports for web and slave agents 67 | EXPOSE 8080 68 | EXPOSE 50000 69 | 70 | COPY plugins.sh /usr/local/bin/plugins.sh 71 | RUN chmod +x /usr/local/bin/plugins.sh 72 | RUN dos2unix /usr/local/bin/plugins.sh 73 | 74 | # Install default plugins 75 | COPY plugins.txt /tmp/plugins.txt 76 | RUN dos2unix /tmp/plugins.txt 77 | 78 | RUN /usr/local/bin/plugins.sh /tmp/plugins.txt 79 | 80 | # Copy in local config files 81 | COPY initagent.groovy /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy 82 | 83 | # Copy startup script 84 | COPY jenkins.sh /usr/local/bin/jenkins.sh 85 | RUN chmod +x /usr/local/bin/jenkins.sh 86 | RUN dos2unix /usr/local/bin/jenkins.sh 87 | 88 | # Setup Jenkins data and folders 89 | COPY jenkinsexport.tar.gz /tmp/jenkinsexport.tar.gz 90 | COPY jenkinsdefaultsecrets.tar.gz /tmp/jenkinsdefaultsecrets.tar.gz 91 | COPY jobs /var/jenkins_home/jobs 92 | RUN tar -xvf /tmp/jenkinsexport.tar.gz && tar -xvf /tmp/jenkinsdefaultsecrets.tar.gz 93 | RUN rm /tmp/jenkinsexport.tar.gz && rm /tmp/jenkinsdefaultsecrets.tar.gz 94 | RUN chown -R jenkins:jenkins /var/jenkins_home 95 | 96 | # Switch to the jenkins user 97 | USER jenkins 98 | 99 | # Tini as the entry point to manage zombie processes 100 | ENTRYPOINT ["/bin/tini", "--", "/usr/local/bin/jenkins.sh"] -------------------------------------------------------------------------------- /jenkins/jenkins-master/initagent.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.*; 2 | import jenkins.model.*; 3 | 4 | 5 | Thread.start { 6 | sleep 10000 7 | println "--> setting agent port for jnlp" 8 | def env = System.getenv() 9 | int port = env['JENKINS_SLAVE_AGENT_PORT'].toInteger() 10 | Jenkins.instance.setSlaveAgentPort(port) 11 | println "--> setting agent port for jnlp... done" 12 | } 13 | -------------------------------------------------------------------------------- /jenkins/jenkins-master/jenkins.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | # Copy files from /usr/share/jenkins/ref into /var/jenkins_home 6 | # So the initial JENKINS-HOME is set with expected content. 7 | # Don't override, as this is just a reference setup, and use from UI 8 | # can then change this, upgrade plugins, etc. 9 | copy_reference_file() { 10 | f=${1%/} 11 | echo "$f" >> $COPY_REFERENCE_FILE_LOG 12 | rel=${f:23} 13 | dir=$(dirname ${f}) 14 | echo " $f -> $rel" >> $COPY_REFERENCE_FILE_LOG 15 | if [[ ! -e /var/jenkins_home/${rel} ]] 16 | then 17 | echo "copy $rel to JENKINS_HOME" >> $COPY_REFERENCE_FILE_LOG 18 | mkdir -p /var/jenkins_home/${dir:23} 19 | cp -r /usr/share/jenkins/ref/${rel} /var/jenkins_home/${rel}; 20 | # pin plugins on initial copy 21 | [[ ${rel} == plugins/*.jpi ]] && touch /var/jenkins_home/${rel}.pinned 22 | fi; 23 | } 24 | export -f copy_reference_file 25 | echo "--- Copying files at $(date)" >> $COPY_REFERENCE_FILE_LOG 26 | find /usr/share/jenkins/ref/ -type f -exec bash -c "copy_reference_file '{}'" \; 27 | 28 | #echo "--- Setting locations ---" 29 | #MYLOC=`cat /myfiles/jenkinslocation.txt` 30 | #echo "Jenkins Location: $MYLOC" 31 | #sed -i "s/.*<\/jenkinsUrl>/http:\/\/$MYLOC\/<\/jenkinsUrl>/g" /var/jenkins_home/jenkins.model.JenkinsLocationConfiguration.xml 32 | #sed -i "s/.*<\/serverUrl>/tcp:\/\/$MYLOC:3375\/<\/serverUrl>/g" /var/jenkins_home/config.xml 33 | #sed -i "s/envVars.put(\"DOCKER_HOST\", \".*\")/envVars.put(\"DOCKER_HOST\", \"tcp:\/\/$MYLOC:3375\")/g" /var/jenkins_home/init.groovy.d/global-env.groovy 34 | #sed -i "s/.*<\/baseUrl>/http:\/\/$MYLOC\/<\/baseUrl>/g" /var/jenkins_home/jenkins.plugins.slack.SlackNotifier.xml 35 | 36 | # if `docker run` first argument start with `--` the user is passing jenkins launcher arguments 37 | if [[ $# -lt 1 ]] || [[ "$1" == "--"* ]]; then 38 | exec java $JAVA_OPTS -Djenkins.install.runSetupWizard=false -jar /usr/share/jenkins/jenkins.war $JENKINS_OPTS "$@" 39 | fi 40 | 41 | # As argument is not jenkins, assume user want to run his own process, for sample a `bash` shell to explore this image 42 | exec "$@" 43 | -------------------------------------------------------------------------------- /jenkins/jenkins-master/jenkinsdefaultsecrets.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxfields2000/dockerjenkins_tutorial/310bfbc78ee5ed7bbde37331455dc2c949262478/jenkins/jenkins-master/jenkinsdefaultsecrets.tar.gz -------------------------------------------------------------------------------- /jenkins/jenkins-master/jenkinsexport.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxfields2000/dockerjenkins_tutorial/310bfbc78ee5ed7bbde37331455dc2c949262478/jenkins/jenkins-master/jenkinsexport.tar.gz -------------------------------------------------------------------------------- /jenkins/jenkins-master/jobs/BasicEnvTest/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | 9 | -1 10 | 1 11 | -1 12 | -1 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 29 | true 30 | 31 | 32 | -------------------------------------------------------------------------------- /jenkins/jenkins-master/plugins.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Parse a support-core plugin -style txt file as specification for jenkins plugins to be installed 4 | # in the reference directory, so user can define a derived Docker image with just : 5 | # 6 | # FROM jenkins 7 | # COPY plugins.txt /plugins.txt 8 | # RUN /usr/local/bin/plugins.sh /plugins.txt 9 | # 10 | 11 | set -e 12 | 13 | REF=/usr/share/jenkins/ref/plugins 14 | mkdir -p $REF 15 | 16 | while read spec || [ -n "$spec" ]; do 17 | plugin=(${spec//:/ }); 18 | [[ ${plugin[0]} =~ ^# ]] && continue 19 | [[ ${plugin[0]} =~ ^\s*$ ]] && continue 20 | [[ -z ${plugin[1]} ]] && plugin[1]="latest" 21 | echo "Downloading ${plugin[0]}:${plugin[1]}" 22 | 23 | if [ -z "$JENKINS_UC_DOWNLOAD" ]; then 24 | JENKINS_UC_DOWNLOAD=$JENKINS_UC/download 25 | fi 26 | curl -sSL -f ${JENKINS_UC_DOWNLOAD}/plugins/${plugin[0]}/${plugin[1]}/${plugin[0]}.hpi -o $REF/${plugin[0]}.jpi 27 | unzip -qqt $REF/${plugin[0]}.jpi 28 | done < $1 29 | -------------------------------------------------------------------------------- /jenkins/jenkins-master/plugins.txt: -------------------------------------------------------------------------------- 1 | ace-editor 1.1 2 | ansicolor 0.5.2 3 | antisamy-markup-formatter 1.5 4 | apache-httpcomponents-client-4-api 4.5.5-2.1 5 | authentication-tokens 1.3 6 | blueocean 1.5.0 7 | blueocean-autofavorite 1.2.2 8 | blueocean-bitbucket-pipeline 1.5.0 9 | blueocean-commons 1.5.0 10 | blueocean-config 1.5.0 11 | blueocean-core-js 1.5.0 12 | blueocean-dashboard 1.5.0 13 | blueocean-display-url 2.2.0 14 | blueocean-events 1.5.0 15 | blueocean-git-pipeline 1.5.0 16 | blueocean-github-pipeline 1.5.0 17 | blueocean-i18n 1.5.0 18 | blueocean-jira 1.5.0 19 | blueocean-jwt 1.5.0 20 | blueocean-personalization 1.5.0 21 | blueocean-pipeline-api-impl 1.5.0 22 | blueocean-pipeline-editor 1.5.0 23 | blueocean-pipeline-scm-api 1.5.0 24 | blueocean-rest 1.5.0 25 | blueocean-rest-impl 1.5.0 26 | blueocean-web 1.5.0 27 | bouncycastle-api 2.16.2 28 | branch-api 2.0.20 29 | build-timeout 1.19 30 | cloud-stats 0.18 31 | cloudbees-bitbucket-branch-source 2.2.11 32 | cloudbees-folder 6.4 33 | command-launcher 1.2 34 | config-file-provider 2.18 35 | credentials 2.1.16 36 | credentials-binding 1.16 37 | display-url-api 2.2.0 38 | docker-commons 1.13 39 | docker-java-api 3.0.14 40 | docker-plugin 1.1.4 41 | docker-workflow 1.17 42 | durable-task 1.22 43 | favorite 2.3.2 44 | git 3.9.0 45 | git-client 2.7.2 46 | git-server 1.7 47 | github 1.29.0 48 | github-api 1.90 49 | github-branch-source 2.3.4 50 | groovy 2.0 51 | handlebars 1.1.1 52 | handy-uri-templates-2-api 2.1.6-1.0 53 | htmlpublisher 1.16 54 | http_request 1.8.22 55 | icon-shim 2.0.3 56 | jackson2-api 2.8.11.2 57 | jclouds-jenkins 2.14 58 | jdk-tool 1.1 59 | jenkins-design-language 1.5.0 60 | jira 3.0.0 61 | job-dsl 1.69 62 | jobConfigHistory 2.18 63 | jquery-detached 1.2.1 64 | jsch 0.1.54.2 65 | junit 1.24 66 | ldap 1.20 67 | mailer 1.21 68 | mapdb-api 1.0.9.0 69 | mask-passwords 2.11.0 70 | matrix-auth 2.2 71 | matrix-project 1.13 72 | mercurial 2.3 73 | metrics 3.1.2.12 74 | metrics-graphite 3.0.0 75 | momentjs 1.1.1 76 | monitoring 1.72.0 77 | pam-auth 1.3 78 | pipeline-aggregator-view 1.8 79 | pipeline-build-step 2.7 80 | pipeline-graph-analysis 1.6 81 | pipeline-input-step 2.8 82 | pipeline-maven 3.5.7 83 | pipeline-milestone-step 1.3.1 84 | pipeline-model-api 1.2.9 85 | pipeline-model-declarative-agent 1.1.1 86 | pipeline-model-definition 1.2.9 87 | pipeline-model-extensions 1.2.9 88 | pipeline-rest-api 2.10 89 | pipeline-stage-step 2.3 90 | pipeline-stage-tags-metadata 1.2.9 91 | pipeline-stage-view 2.10 92 | pipeline-utility-steps 2.1.0 93 | plain-credentials 1.4 94 | pubsub-light 1.12 95 | resource-disposer 0.8 96 | scm-api 2.2.7 97 | script-security 1.44 98 | sse-gateway 1.15 99 | ssh-agent 1.15 100 | ssh-credentials 1.13 101 | ssh-slaves 1.26 102 | structs 1.14 103 | subversion 2.10.6 104 | timestamper 1.8.10 105 | token-macro 2.5 106 | variant 1.1 107 | windows-slaves 1.3.1 108 | workflow-aggregator 2.5 109 | workflow-api 2.27 110 | workflow-basic-steps 2.7 111 | workflow-cps 2.53 112 | workflow-cps-global-lib 2.9 113 | workflow-durable-task-step 2.19 114 | workflow-job 2.21 115 | workflow-multibranch 2.19 116 | workflow-scm-step 2.6 117 | workflow-step-api 2.15 118 | workflow-support 2.18 -------------------------------------------------------------------------------- /jenkins/jenkins-nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Install NGINX 5 | RUN yum -y update; yum clean all 6 | RUN yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm; yum -y makecache 7 | RUN yum -y install nginx-1.10.1 8 | 9 | # Remove default files we don't need 10 | RUN rm /etc/nginx/conf.d/default.conf 11 | 12 | # Add default configuration 13 | COPY conf/jenkins.conf /etc/nginx/conf.d/jenkins.conf 14 | COPY conf/nginx.conf /etc/nginx/nginx.conf 15 | 16 | EXPOSE 80 17 | 18 | CMD ["nginx"] -------------------------------------------------------------------------------- /jenkins/jenkins-nginx/conf/jenkins.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name ""; 4 | 5 | access_log off; 6 | 7 | location / { 8 | proxy_pass http://jenkins_master_1:8080; 9 | 10 | proxy_set_header Host $host; 11 | proxy_set_header X-Real-IP $remote_addr; 12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 13 | proxy_set_header X-Forwarded-Proto http; 14 | proxy_max_temp_file_size 0; 15 | 16 | proxy_connect_timeout 150; 17 | proxy_send_timeout 100; 18 | proxy_read_timeout 100; 19 | 20 | proxy_buffer_size 8k; 21 | proxy_buffers 4 32k; 22 | proxy_busy_buffers_size 64k; 23 | proxy_temp_file_write_size 64k; 24 | 25 | 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /jenkins/jenkins-nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | user nginx; 3 | worker_processes 2; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | use epoll; 12 | accept_mutex off; 13 | } 14 | 15 | 16 | http { 17 | include /etc/nginx/mime.types; 18 | proxy_set_header X-Real-IP $remote_addr; 19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | 21 | default_type application/octet-stream; 22 | 23 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 24 | '$status $body_bytes_sent "$http_referer" ' 25 | '"$http_user_agent" "$http_x_forwarded_for"'; 26 | 27 | access_log /var/log/nginx/access.log main; 28 | 29 | sendfile on; 30 | #tcp_nopush on; 31 | 32 | keepalive_timeout 65; 33 | 34 | client_max_body_size 300m; 35 | client_body_buffer_size 128k; 36 | 37 | gzip on; 38 | gzip_http_version 1.0; 39 | gzip_comp_level 6; 40 | gzip_min_length 0; 41 | gzip_buffers 16 8k; 42 | gzip_proxied any; 43 | gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json; 44 | gzip_disable "MSIE [1-6]\."; 45 | gzip_vary on; 46 | 47 | include /etc/nginx/conf.d/*.conf; 48 | } 49 | -------------------------------------------------------------------------------- /jenkins/jenkins-slave/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Install Essentials 5 | RUN yum update -y && \ 6 | yum clean all 7 | 8 | # Install Packages 9 | RUN yum install -y git && \ 10 | yum install -y wget && \ 11 | yum install -y java-1.8.0-openjdk && \ 12 | yum install -y sudo && \ 13 | yum clean all 14 | 15 | ARG user=jenkins 16 | ARG group=jenkins 17 | ARG uid=1000 18 | ARG gid=1000 19 | 20 | ENV JENKINS_HOME /home/${user} 21 | 22 | # Jenkins is run with user `jenkins`, uid = 1000 23 | RUN groupadd -g ${gid} ${group} \ 24 | && useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user} 25 | 26 | RUN chown -R ${user}:${user} /home/${user} 27 | 28 | # Add the jenkins user to sudoers 29 | RUN echo "${user} ALL=(ALL) ALL" >> etc/sudoers 30 | 31 | # Set Name Servers 32 | COPY /files/resolv.conf /etc/resolv.conf 33 | 34 | -------------------------------------------------------------------------------- /jenkins/jenkins-slave/files/resolv.conf: -------------------------------------------------------------------------------- 1 | nameserver 8.8.8.8 2 | nameserver 8.8.4.4 3 | -------------------------------------------------------------------------------- /jenkins/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker-compose -p jenkins build 3 | run: 4 | @docker-compose -p jenkins up -d nginx master proxy 5 | run-win: 6 | @docker-compose -p jenkins up -d nginx master 7 | stop: 8 | @docker-compose -p jenkins down 9 | clean-data: 10 | @docker-compose -p jenkins down -v 11 | clean-images: 12 | @docker rmi `docker images -q -f "dangling=true"` 13 | ps: 14 | @docker-compose -p jenkins ps 15 | jenkins-log: 16 | @docker-compose -p jenkins exec master tail -f /var/log/jenkins/jenkins.log 17 | 18 | -------------------------------------------------------------------------------- /jenkinsscripts/README.md: -------------------------------------------------------------------------------- 1 | # Scriptler Scripts for API Control of Docker Plugins 2 | 3 | These scripts are provided as is. To use them, make sure your Jenkins environment has the "Scriptler" plugin installed. Add these groovy scripts as Scriptler groovy scripts to your jenkins configuration. Please note at this time Scriptler is considered a potential security risk because of its ability to execute code on the master server. Use wisely! 4 | 5 | #inputs 6 | 7 | Create these input variables to each script (for the API): 8 | 9 | * cloudName existing or current docker cloud name 10 | * label desired label for build node 11 | * image image location (eg. dockers.tf.riotgames...) 12 | 13 | # Notes 14 | 15 | The Regular Dockerplugin groovy script assumes your build slaves connect via SSH. This also requires a "credentialsId" UUID, which Left out of my example for 16 | obvious security reasons, please add your own! 17 | 18 | The Yet Another Docker Plugin assumes you're using JNLP connections, not SSH ones (recommended approach for YADP) and therefor doesn't use a credentials Id. 19 | 20 | # Questions 21 | 22 | If you have questions please freel free to ask. These are part of my 2016 Dockercon presentation! -------------------------------------------------------------------------------- /jenkinsscripts/addDockerPluginTemplate.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.* 2 | import jenkins.model.* 3 | import hudson.* 4 | import hudson.model.* 5 | 6 | import com.nirima.jenkins.plugins.docker.* 7 | import hudson.plugins.sshslaves.SSHConnector 8 | import com.nirima.jenkins.plugins.docker.launcher.* 9 | import com.nirima.jenkins.plugins.docker.strategy.* 10 | 11 | 12 | /* 13 | ================================= 14 | = NEW TEMPLATE HARDCODED VALUES = 15 | ================================= 16 | */ 17 | def remoteFs = "/home/jenkins" 18 | def remoteFsMapping = "" 19 | def idleTerminationMinutes = "5" 20 | def launchTimeoutMinutes = 1 21 | def jvmOptions = "" 22 | def javaPath = "" 23 | def prefixStartSlaveCmd = "" 24 | def suffixStartSlaveCmd = "" 25 | def instanceCapStr = "" 26 | def dnsString = "10.201.17.11" 27 | def dockerCommand = "" 28 | def volumesString = "" 29 | def volumesFrom = "" 30 | def lxcConfString = "" 31 | def hostname = "" 32 | def bindPorts ="" 33 | def bindAllPorts = false 34 | def privileged = false 35 | def environment = "" 36 | def memoryLimit = null 37 | def cpuShares = null 38 | def tty = false 39 | def macAddress = "" 40 | def numExecutors = 1 41 | def mode = Node.Mode.EXCLUSIVE 42 | def idleMinutes = 5 43 | def removeVolumes = true 44 | 45 | /* This works because we want to pull only when an image doesn't exist on the box, 46 | * OR the image ends with :latest. :lkg images will not end up pulling if the image is 47 | * on the box already. 48 | */ 49 | def pullStrategy = DockerImagePullStrategy.PULL_LATEST 50 | 51 | /* 52 | * Checks if specified label is in any docker cloud 53 | * dockerServer list of cloudhosts from docker plugin 54 | * return true if label is found 55 | */ 56 | def labelInCloud(dockerServers) { 57 | def found = false 58 | dockerServers.each() { dockerServer -> 59 | //label checking 60 | ArrayList templates = dockerServer.templates 61 | templates.each() { template -> 62 | if (template.labelString.toLowerCase().equals(label.toLowerCase())) { 63 | found = true 64 | } 65 | } 66 | } 67 | return found 68 | } 69 | 70 | /* 71 | =============================== 72 | = ADDING NEW DOCKER HOST CODE = 73 | =============================== 74 | */ 75 | //injected variables from jenkins envinject: 76 | //cloudName existing or current docker cloud name 77 | //label desired label for build node 78 | //image image location (eg. dockers.tf.riotgames...) 79 | def dockerPlugin = Jenkins.instance.pluginManager.getPlugin("docker-plugin").getPlugin() 80 | def dockerServers = dockerPlugin.getServers() 81 | def cloudExists = false 82 | def labelExists = labelInCloud(dockerServers) 83 | if (label.equals("")) { 84 | println("Label cannot be empty. Slave not added") 85 | } else if (labelExists) { 86 | println("Specified label already exists. Slave not added.") 87 | } else { 88 | dockerServers.each() { dockerServer -> 89 | //label checking 90 | ArrayList templates = dockerServer.templates 91 | if (dockerServer.name.toLowerCase().equals(cloudName.toLowerCase())) { 92 | cloudExists = true 93 | println("Adding "+ label + " to cloud[" + cloudName + "]...") 94 | def retentionStrategy = new DockerOnceRetentionStrategy(idleMinutes) 95 | def sshConnector = new SSHConnector(22, credentialsId, jvmOptions, javaPath, prefixStartSlaveCmd, 96 | suffixStartSlaveCmd, launchTimeoutMinutes * 60) 97 | def launcher = new DockerComputerSSHLauncher(sshConnector) 98 | def templateBase = new DockerTemplateBase(image, dnsString, dockerCommand, volumesString, 99 | volumesFrom, environment, lxcConfString, hostname, 100 | memoryLimit, cpuShares, bindPorts, bindAllPorts, 101 | privileged, tty, macAddress) 102 | 103 | def template = new DockerTemplate(templateBase, label, remoteFs, remoteFsMapping, instanceCapStr, 104 | mode, numExecutors, launcher, retentionStrategy, removeVolumes, 105 | pullStrategy) 106 | templates.add(template) 107 | } 108 | } 109 | if (!cloudExists) { 110 | println("Cloud not found. Please specify a currently existing cloud.") 111 | } 112 | } 113 | println() -------------------------------------------------------------------------------- /jenkinsscripts/addYATDPluginTemplate.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.* 2 | import jenkins.model.* 3 | import hudson.* 4 | import hudson.model.* 5 | import hudson.security.ACL; 6 | import hudson.slaves.*; 7 | import static java.util.Collections.singletonList; 8 | import com.github.kostyasha.yad.commons.*; 9 | import com.github.kostyasha.yad.DockerCloud; 10 | import com.github.kostyasha.yad.DockerContainerLifecycle; 11 | import com.github.kostyasha.yad.DockerSlaveTemplate; 12 | import com.github.kostyasha.yad.launcher.DockerComputerJNLPLauncher; 13 | import com.github.kostyasha.yad.strategy.DockerOnceRetentionStrategy; 14 | 15 | // Let's find the cloud! 16 | def myCloud = Jenkins.instance.getInstance().getCloud(cloudName); 17 | 18 | if (!myCloud) { 19 | println("Cloud not found, aborting.") 20 | return false 21 | } 22 | 23 | if (label == "") { 24 | println("Labels can't be empty strings, aborting.") 25 | return false 26 | } 27 | 28 | if (image == "") { 29 | println("Image names can't be empty strings, aborting.") 30 | return false 31 | } 32 | 33 | def launcher = new DockerComputerJNLPLauncher(new JNLPLauncher()); 34 | launcher.setUser("jenkins"); 35 | launcher.setLaunchTimeout(60); 36 | 37 | def pullImage = new DockerPullImage(); 38 | pullImage.setPullStrategy(DockerImagePullStrategy.PULL_NEVER); 39 | 40 | //remove 41 | def removeContainer = new DockerRemoveContainer(); 42 | removeContainer.setRemoveVolumes(true); 43 | removeContainer.setForce(true); 44 | 45 | // Container details 46 | def createContainer = new DockerCreateContainer(); 47 | 48 | //lifecycle 49 | def containerLifecycle = new DockerContainerLifecycle(); 50 | containerLifecycle.setImage(image); 51 | containerLifecycle.setPullImage(pullImage); 52 | containerLifecycle.setRemoveContainer(removeContainer); 53 | containerLifecycle.setCreateContainer(createContainer); 54 | 55 | //Node Properties (environment variables) 56 | def nodeProperties = new ArrayList<>(); 57 | 58 | def slaveTemplate = new DockerSlaveTemplate(); 59 | slaveTemplate.setLabelString(label); 60 | slaveTemplate.setLauncher(launcher); 61 | slaveTemplate.setMode(Node.Mode.EXCLUSIVE); 62 | slaveTemplate.setRetentionStrategy(new DockerOnceRetentionStrategy(5)); 63 | slaveTemplate.setDockerContainerLifecycle(containerLifecycle); 64 | slaveTemplate.setNodeProperties(nodeProperties); 65 | slaveTemplate.setRemoteFsMapping("/home/jenkins"); 66 | 67 | def templates = myCloud.getTemplates(); 68 | def newTemplates = new ArrayList(); 69 | newTemplates.addAll(templates); 70 | newTemplates.add(slaveTemplate); 71 | 72 | myCloud.setTemplates(newTemplates); 73 | Jenkins.getActiveInstance().save(); 74 | 75 | return true -------------------------------------------------------------------------------- /monitoring/JenkinsMetrics.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_LOCALGRAPHITE", 5 | "label": "LocalGraphite", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "graphite", 9 | "pluginName": "Graphite" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "4.2.0" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "graphite", 28 | "name": "Graphite", 29 | "version": "1.0.0" 30 | }, 31 | { 32 | "type": "panel", 33 | "id": "singlestat", 34 | "name": "Singlestat", 35 | "version": "" 36 | }, 37 | { 38 | "type": "panel", 39 | "id": "text", 40 | "name": "Text", 41 | "version": "" 42 | } 43 | ], 44 | "annotations": { 45 | "list": [] 46 | }, 47 | "editable": true, 48 | "gnetId": null, 49 | "graphTooltip": 1, 50 | "hideControls": false, 51 | "id": null, 52 | "links": [], 53 | "refresh": "1m", 54 | "rows": [ 55 | { 56 | "collapse": false, 57 | "height": "25px", 58 | "panels": [ 59 | { 60 | "content": "

$Server

", 61 | "editable": true, 62 | "error": false, 63 | "id": 23, 64 | "links": [], 65 | "mode": "html", 66 | "span": 12, 67 | "style": {}, 68 | "title": "", 69 | "type": "text" 70 | } 71 | ], 72 | "repeat": null, 73 | "repeatIteration": null, 74 | "repeatRowId": null, 75 | "showTitle": false, 76 | "title": "New row", 77 | "titleSize": "h6" 78 | }, 79 | { 80 | "collapse": false, 81 | "height": "250px", 82 | "panels": [ 83 | { 84 | "aliasColors": {}, 85 | "bars": false, 86 | "datasource": "${DS_LOCALGRAPHITE}", 87 | "editable": true, 88 | "error": false, 89 | "fill": 1, 90 | "grid": {}, 91 | "hideTimeOverride": true, 92 | "id": 6, 93 | "legend": { 94 | "avg": false, 95 | "current": false, 96 | "max": false, 97 | "min": false, 98 | "show": true, 99 | "total": false, 100 | "values": false 101 | }, 102 | "lines": true, 103 | "linewidth": 2, 104 | "links": [], 105 | "maxDataPoints": "", 106 | "nullPointMode": "connected", 107 | "percentage": false, 108 | "pointradius": 5, 109 | "points": false, 110 | "renderer": "flot", 111 | "seriesOverrides": [ 112 | { 113 | "alias": "max", 114 | "color": "#58140C", 115 | "fill": 0, 116 | "stack": false 117 | } 118 | ], 119 | "span": 4, 120 | "stack": true, 121 | "steppedLine": false, 122 | "targets": [ 123 | { 124 | "refId": "A", 125 | "target": "alias($Server.vm.memory.non-heap.used, 'non-heap')" 126 | }, 127 | { 128 | "refId": "B", 129 | "target": "alias($Server.vm.memory.heap.used, 'heap')" 130 | }, 131 | { 132 | "refId": "C", 133 | "target": "alias($Server.vm.memory.heap.max, 'max')" 134 | } 135 | ], 136 | "thresholds": [], 137 | "timeFrom": null, 138 | "timeShift": "5m", 139 | "title": "Heap Memory", 140 | "tooltip": { 141 | "shared": true, 142 | "sort": 0, 143 | "value_type": "cumulative" 144 | }, 145 | "type": "graph", 146 | "xaxis": { 147 | "mode": "time", 148 | "name": null, 149 | "show": true, 150 | "values": [] 151 | }, 152 | "yaxes": [ 153 | { 154 | "format": "bytes", 155 | "logBase": 1, 156 | "max": null, 157 | "min": 0, 158 | "show": true 159 | }, 160 | { 161 | "format": "short", 162 | "logBase": 1, 163 | "max": null, 164 | "min": null, 165 | "show": true 166 | } 167 | ] 168 | }, 169 | { 170 | "aliasColors": {}, 171 | "bars": false, 172 | "datasource": "${DS_LOCALGRAPHITE}", 173 | "editable": true, 174 | "error": false, 175 | "fill": 1, 176 | "grid": {}, 177 | "hideTimeOverride": true, 178 | "id": 2, 179 | "legend": { 180 | "avg": false, 181 | "current": false, 182 | "max": false, 183 | "min": false, 184 | "show": true, 185 | "total": false, 186 | "values": false 187 | }, 188 | "lines": true, 189 | "linewidth": 2, 190 | "links": [], 191 | "nullPointMode": "connected", 192 | "percentage": false, 193 | "pointradius": 5, 194 | "points": false, 195 | "renderer": "flot", 196 | "seriesOverrides": [ 197 | { 198 | "alias": "pending", 199 | "color": "#E5AC0E" 200 | }, 201 | { 202 | "alias": "buildable", 203 | "color": "#629E51" 204 | }, 205 | { 206 | "alias": "blocked", 207 | "color": "#962D82" 208 | }, 209 | { 210 | "alias": "stuck", 211 | "color": "#58140C" 212 | }, 213 | { 214 | "alias": "overall", 215 | "color": "#052B51", 216 | "fill": 0, 217 | "stack": false 218 | } 219 | ], 220 | "span": 4, 221 | "stack": true, 222 | "steppedLine": true, 223 | "targets": [ 224 | { 225 | "hide": false, 226 | "refId": "A", 227 | "target": "alias($Server.jenkins.queue.stuck.value, 'stuck')" 228 | }, 229 | { 230 | "refId": "B", 231 | "target": "alias($Server.jenkins.queue.pending.value, 'pending')" 232 | }, 233 | { 234 | "refId": "C", 235 | "target": "alias($Server.jenkins.queue.blocked.value, 'blocked')" 236 | }, 237 | { 238 | "refId": "D", 239 | "target": "alias($Server.jenkins.queue.buildable.value, 'buildable')" 240 | }, 241 | { 242 | "refId": "E", 243 | "target": "alias($Server.jenkins.queue.size.value, 'overall')" 244 | } 245 | ], 246 | "thresholds": [], 247 | "timeFrom": null, 248 | "timeShift": "5m", 249 | "title": "Queue Size", 250 | "tooltip": { 251 | "shared": true, 252 | "sort": 0, 253 | "value_type": "individual" 254 | }, 255 | "type": "graph", 256 | "xaxis": { 257 | "mode": "time", 258 | "name": null, 259 | "show": true, 260 | "values": [] 261 | }, 262 | "yaxes": [ 263 | { 264 | "format": "short", 265 | "logBase": 1, 266 | "max": null, 267 | "min": 0, 268 | "show": true 269 | }, 270 | { 271 | "format": "short", 272 | "logBase": 1, 273 | "max": null, 274 | "min": null, 275 | "show": true 276 | } 277 | ] 278 | }, 279 | { 280 | "aliasColors": {}, 281 | "bars": false, 282 | "datasource": "${DS_LOCALGRAPHITE}", 283 | "editable": true, 284 | "error": false, 285 | "fill": 1, 286 | "grid": {}, 287 | "hideTimeOverride": true, 288 | "id": 8, 289 | "legend": { 290 | "avg": false, 291 | "current": false, 292 | "max": false, 293 | "min": false, 294 | "show": true, 295 | "total": false, 296 | "values": false 297 | }, 298 | "lines": true, 299 | "linewidth": 2, 300 | "links": [], 301 | "nullPointMode": "connected", 302 | "percentage": false, 303 | "pointradius": 5, 304 | "points": false, 305 | "renderer": "flot", 306 | "seriesOverrides": [ 307 | { 308 | "alias": "failure", 309 | "color": "#BF1B00" 310 | }, 311 | { 312 | "alias": "success", 313 | "color": "#7EB26D" 314 | } 315 | ], 316 | "span": 4, 317 | "stack": true, 318 | "steppedLine": false, 319 | "targets": [ 320 | { 321 | "refId": "A", 322 | "target": "alias($Server.jenkins.runs.failure.m1_rate, 'failure')" 323 | }, 324 | { 325 | "refId": "B", 326 | "target": "alias($Server.jenkins.runs.success.m1_rate, 'success')" 327 | } 328 | ], 329 | "thresholds": [], 330 | "timeFrom": null, 331 | "timeShift": "5m", 332 | "title": "Jobs Per Minute", 333 | "tooltip": { 334 | "shared": true, 335 | "sort": 0, 336 | "value_type": "individual" 337 | }, 338 | "type": "graph", 339 | "xaxis": { 340 | "mode": "time", 341 | "name": null, 342 | "show": true, 343 | "values": [] 344 | }, 345 | "yaxes": [ 346 | { 347 | "format": "none", 348 | "label": "", 349 | "logBase": 1, 350 | "max": null, 351 | "min": 0, 352 | "show": true 353 | }, 354 | { 355 | "format": "short", 356 | "logBase": 1, 357 | "max": null, 358 | "min": null, 359 | "show": true 360 | } 361 | ] 362 | } 363 | ], 364 | "repeat": null, 365 | "repeatIteration": null, 366 | "repeatRowId": null, 367 | "showTitle": false, 368 | "title": "Row", 369 | "titleSize": "h6" 370 | }, 371 | { 372 | "collapse": false, 373 | "height": "250px", 374 | "panels": [ 375 | { 376 | "aliasColors": {}, 377 | "bars": false, 378 | "datasource": "${DS_LOCALGRAPHITE}", 379 | "editable": true, 380 | "error": false, 381 | "fill": 1, 382 | "grid": {}, 383 | "id": 15, 384 | "legend": { 385 | "avg": false, 386 | "current": false, 387 | "max": false, 388 | "min": false, 389 | "show": true, 390 | "total": false, 391 | "values": false 392 | }, 393 | "lines": true, 394 | "linewidth": 2, 395 | "links": [], 396 | "nullPointMode": "connected", 397 | "percentage": false, 398 | "pointradius": 5, 399 | "points": false, 400 | "renderer": "flot", 401 | "seriesOverrides": [], 402 | "span": 4, 403 | "stack": false, 404 | "steppedLine": false, 405 | "targets": [ 406 | { 407 | "refId": "A", 408 | "target": "alias($Server.vm.memory.pools.PS-Old-Gen.usage, 'Old Gen')" 409 | } 410 | ], 411 | "thresholds": [], 412 | "timeFrom": null, 413 | "timeShift": null, 414 | "title": "Old-Gen Space", 415 | "tooltip": { 416 | "shared": true, 417 | "sort": 0, 418 | "value_type": "cumulative" 419 | }, 420 | "type": "graph", 421 | "xaxis": { 422 | "mode": "time", 423 | "name": null, 424 | "show": true, 425 | "values": [] 426 | }, 427 | "yaxes": [ 428 | { 429 | "format": "percentunit", 430 | "logBase": 1, 431 | "max": 1, 432 | "min": 0, 433 | "show": true 434 | }, 435 | { 436 | "format": "short", 437 | "logBase": 1, 438 | "max": null, 439 | "min": null, 440 | "show": true 441 | } 442 | ] 443 | }, 444 | { 445 | "aliasColors": {}, 446 | "bars": false, 447 | "datasource": "${DS_LOCALGRAPHITE}", 448 | "editable": true, 449 | "error": false, 450 | "fill": 1, 451 | "grid": {}, 452 | "id": 9, 453 | "legend": { 454 | "avg": false, 455 | "current": false, 456 | "max": false, 457 | "min": false, 458 | "show": true, 459 | "total": false, 460 | "values": false 461 | }, 462 | "lines": true, 463 | "linewidth": 2, 464 | "links": [], 465 | "nullPointMode": "connected", 466 | "percentage": false, 467 | "pointradius": 5, 468 | "points": false, 469 | "renderer": "flot", 470 | "seriesOverrides": [ 471 | { 472 | "alias": "in-use", 473 | "color": "#E5AC0E" 474 | }, 475 | { 476 | "alias": "free", 477 | "color": "#7EB26D" 478 | } 479 | ], 480 | "span": 4, 481 | "stack": true, 482 | "steppedLine": false, 483 | "targets": [ 484 | { 485 | "refId": "A", 486 | "target": "alias($Server.jenkins.executor.free.value, 'free')" 487 | }, 488 | { 489 | "refId": "B", 490 | "target": "alias($Server.jenkins.executor.in-use.value, 'in-use')" 491 | } 492 | ], 493 | "thresholds": [], 494 | "timeFrom": null, 495 | "timeShift": null, 496 | "title": "Executors", 497 | "tooltip": { 498 | "shared": true, 499 | "sort": 0, 500 | "value_type": "individual" 501 | }, 502 | "type": "graph", 503 | "xaxis": { 504 | "mode": "time", 505 | "name": null, 506 | "show": true, 507 | "values": [] 508 | }, 509 | "yaxes": [ 510 | { 511 | "format": "short", 512 | "logBase": 1, 513 | "max": null, 514 | "min": 0, 515 | "show": true 516 | }, 517 | { 518 | "format": "short", 519 | "logBase": 1, 520 | "max": null, 521 | "min": null, 522 | "show": true 523 | } 524 | ] 525 | }, 526 | { 527 | "aliasColors": {}, 528 | "bars": true, 529 | "datasource": "${DS_LOCALGRAPHITE}", 530 | "editable": true, 531 | "error": false, 532 | "fill": 1, 533 | "grid": {}, 534 | "hideTimeOverride": true, 535 | "id": 16, 536 | "legend": { 537 | "avg": false, 538 | "current": false, 539 | "max": false, 540 | "min": false, 541 | "show": true, 542 | "total": false, 543 | "values": false 544 | }, 545 | "lines": false, 546 | "linewidth": 2, 547 | "links": [], 548 | "nullPointMode": "connected", 549 | "percentage": false, 550 | "pointradius": 5, 551 | "points": false, 552 | "renderer": "flot", 553 | "seriesOverrides": [ 554 | { 555 | "alias": "success", 556 | "color": "#508642" 557 | }, 558 | { 559 | "alias": "failure", 560 | "color": "#58140C" 561 | }, 562 | { 563 | "alias": "aborted", 564 | "color": "#705DA0" 565 | } 566 | ], 567 | "span": 4, 568 | "stack": true, 569 | "steppedLine": false, 570 | "targets": [ 571 | { 572 | "refId": "A", 573 | "target": "alias(derivative(summarize($Server.jenkins.runs.success.count, '1hour', 'avg')), 'success')", 574 | "textEditor": false 575 | }, 576 | { 577 | "refId": "B", 578 | "target": "alias(derivative(summarize($Server.jenkins.runs.failure.count, '1h', 'avg')), 'failure')" 579 | }, 580 | { 581 | "refId": "C", 582 | "target": "alias(derivative(summarize($Server.jenkins.runs.aborted.count, '1h', 'avg')), 'aborted')" 583 | } 584 | ], 585 | "thresholds": [], 586 | "timeFrom": null, 587 | "timeShift": "5m", 588 | "title": "Job Per Hour", 589 | "tooltip": { 590 | "shared": true, 591 | "sort": 0, 592 | "value_type": "individual" 593 | }, 594 | "type": "graph", 595 | "xaxis": { 596 | "mode": "time", 597 | "name": null, 598 | "show": true, 599 | "values": [] 600 | }, 601 | "yaxes": [ 602 | { 603 | "format": "short", 604 | "logBase": 1, 605 | "max": null, 606 | "min": 0, 607 | "show": true 608 | }, 609 | { 610 | "format": "short", 611 | "logBase": 1, 612 | "max": null, 613 | "min": null, 614 | "show": true 615 | } 616 | ] 617 | } 618 | ], 619 | "repeat": null, 620 | "repeatIteration": null, 621 | "repeatRowId": null, 622 | "showTitle": false, 623 | "title": "New row", 624 | "titleSize": "h6" 625 | }, 626 | { 627 | "collapse": false, 628 | "height": "250px", 629 | "panels": [ 630 | { 631 | "aliasColors": {}, 632 | "bars": false, 633 | "datasource": "${DS_LOCALGRAPHITE}", 634 | "editable": true, 635 | "error": false, 636 | "fill": 1, 637 | "grid": {}, 638 | "id": 14, 639 | "legend": { 640 | "avg": false, 641 | "current": false, 642 | "max": false, 643 | "min": false, 644 | "show": true, 645 | "total": false, 646 | "values": false 647 | }, 648 | "lines": true, 649 | "linewidth": 2, 650 | "links": [], 651 | "nullPointMode": "connected", 652 | "percentage": false, 653 | "pointradius": 5, 654 | "points": false, 655 | "renderer": "flot", 656 | "seriesOverrides": [ 657 | { 658 | "alias": "Eden Space", 659 | "color": "#806EB7" 660 | }, 661 | { 662 | "alias": "Survivor Space", 663 | "transform": "negative-Y" 664 | } 665 | ], 666 | "span": 4, 667 | "stack": false, 668 | "steppedLine": false, 669 | "targets": [ 670 | { 671 | "refId": "B", 672 | "target": "alias($Server.vm.memory.pools.PS-Eden-Space.usage, 'Eden Space')" 673 | }, 674 | { 675 | "refId": "D", 676 | "target": "alias($Server.vm.memory.pools.PS-Survivor-Space.usage, 'Survivor Space')" 677 | } 678 | ], 679 | "thresholds": [], 680 | "timeFrom": null, 681 | "timeShift": null, 682 | "title": "Memory Pools Eden/Survivor", 683 | "tooltip": { 684 | "shared": true, 685 | "sort": 0, 686 | "value_type": "cumulative" 687 | }, 688 | "type": "graph", 689 | "xaxis": { 690 | "mode": "time", 691 | "name": null, 692 | "show": true, 693 | "values": [] 694 | }, 695 | "yaxes": [ 696 | { 697 | "format": "percentunit", 698 | "logBase": 1, 699 | "max": null, 700 | "min": null, 701 | "show": true 702 | }, 703 | { 704 | "format": "short", 705 | "logBase": 1, 706 | "max": null, 707 | "min": null, 708 | "show": true 709 | } 710 | ] 711 | }, 712 | { 713 | "aliasColors": {}, 714 | "bars": false, 715 | "datasource": "${DS_LOCALGRAPHITE}", 716 | "editable": true, 717 | "error": false, 718 | "fill": 1, 719 | "grid": {}, 720 | "id": 24, 721 | "legend": { 722 | "avg": false, 723 | "current": false, 724 | "max": false, 725 | "min": false, 726 | "show": true, 727 | "total": false, 728 | "values": false 729 | }, 730 | "lines": true, 731 | "linewidth": 2, 732 | "links": [], 733 | "nullPointMode": "connected", 734 | "percentage": false, 735 | "pointradius": 5, 736 | "points": false, 737 | "renderer": "flot", 738 | "seriesOverrides": [ 739 | { 740 | "alias": "deadlock", 741 | "color": "#58140C" 742 | }, 743 | { 744 | "alias": "timed_waiting", 745 | "color": "#EAB839" 746 | }, 747 | { 748 | "alias": "runnable", 749 | "color": "#629E51" 750 | }, 751 | { 752 | "alias": "waiting", 753 | "color": "#C15C17" 754 | }, 755 | { 756 | "alias": "new", 757 | "color": "#1F78C1" 758 | }, 759 | { 760 | "alias": "blocked", 761 | "color": "#D683CE" 762 | } 763 | ], 764 | "span": 4, 765 | "stack": true, 766 | "steppedLine": false, 767 | "targets": [ 768 | { 769 | "refId": "A", 770 | "target": "alias($Server.vm.deadlock.count, 'deadlock')", 771 | "textEditor": true 772 | }, 773 | { 774 | "refId": "B", 775 | "target": "alias($Server.vm.waiting.count, 'waiting')" 776 | }, 777 | { 778 | "refId": "C", 779 | "target": "alias($Server.vm.timed_waiting.count, 'timed_waiting')", 780 | "textEditor": true 781 | }, 782 | { 783 | "refId": "D", 784 | "target": "alias($Server.vm.blocked.count, 'blocked')" 785 | }, 786 | { 787 | "refId": "E", 788 | "target": "alias($Server.vm.runnable.count, 'runnable')" 789 | }, 790 | { 791 | "refId": "F", 792 | "target": "alias($Server.vm.new.count, 'new')" 793 | } 794 | ], 795 | "thresholds": [], 796 | "timeFrom": null, 797 | "timeShift": null, 798 | "title": "Thread Status", 799 | "tooltip": { 800 | "shared": true, 801 | "sort": 0, 802 | "value_type": "individual" 803 | }, 804 | "type": "graph", 805 | "xaxis": { 806 | "mode": "time", 807 | "name": null, 808 | "show": true, 809 | "values": [] 810 | }, 811 | "yaxes": [ 812 | { 813 | "format": "short", 814 | "logBase": 1, 815 | "max": null, 816 | "min": null, 817 | "show": true 818 | }, 819 | { 820 | "format": "short", 821 | "logBase": 1, 822 | "max": null, 823 | "min": null, 824 | "show": true 825 | } 826 | ] 827 | }, 828 | { 829 | "aliasColors": {}, 830 | "bars": false, 831 | "datasource": "${DS_LOCALGRAPHITE}", 832 | "editable": true, 833 | "error": false, 834 | "fill": 1, 835 | "grid": {}, 836 | "hideTimeOverride": true, 837 | "id": 4, 838 | "legend": { 839 | "avg": false, 840 | "current": true, 841 | "max": false, 842 | "min": false, 843 | "show": true, 844 | "total": false, 845 | "values": true 846 | }, 847 | "lines": true, 848 | "linewidth": 2, 849 | "links": [], 850 | "nullPointMode": "connected", 851 | "percentage": false, 852 | "pointradius": 5, 853 | "points": false, 854 | "renderer": "flot", 855 | "seriesOverrides": [ 856 | { 857 | "alias": "offline", 858 | "color": "#58140C" 859 | }, 860 | { 861 | "alias": "online", 862 | "color": "#7EB26D" 863 | } 864 | ], 865 | "span": 4, 866 | "stack": true, 867 | "steppedLine": true, 868 | "targets": [ 869 | { 870 | "refId": "A", 871 | "target": "alias($Server.jenkins.node.offline.value, 'offline')" 872 | }, 873 | { 874 | "refId": "B", 875 | "target": "alias($Server.jenkins.node.online.value, 'online')" 876 | } 877 | ], 878 | "thresholds": [], 879 | "timeFrom": null, 880 | "timeShift": "5m", 881 | "title": "Total Nodes", 882 | "tooltip": { 883 | "shared": true, 884 | "sort": 0, 885 | "value_type": "individual" 886 | }, 887 | "type": "graph", 888 | "xaxis": { 889 | "mode": "time", 890 | "name": null, 891 | "show": true, 892 | "values": [] 893 | }, 894 | "yaxes": [ 895 | { 896 | "format": "short", 897 | "logBase": 1, 898 | "max": null, 899 | "min": 0, 900 | "show": true 901 | }, 902 | { 903 | "format": "short", 904 | "logBase": 1, 905 | "max": null, 906 | "min": null, 907 | "show": true 908 | } 909 | ] 910 | } 911 | ], 912 | "repeat": null, 913 | "repeatIteration": null, 914 | "repeatRowId": null, 915 | "showTitle": false, 916 | "title": "New row", 917 | "titleSize": "h6" 918 | }, 919 | { 920 | "collapse": false, 921 | "height": "100px", 922 | "panels": [ 923 | { 924 | "cacheTimeout": null, 925 | "colorBackground": false, 926 | "colorValue": true, 927 | "colors": [ 928 | "rgba(245, 54, 54, 0.9)", 929 | "rgba(237, 129, 40, 0.89)", 930 | "rgba(50, 172, 45, 0.97)" 931 | ], 932 | "datasource": "${DS_LOCALGRAPHITE}", 933 | "editable": true, 934 | "error": false, 935 | "format": "none", 936 | "gauge": { 937 | "maxValue": 100, 938 | "minValue": 0, 939 | "show": false, 940 | "thresholdLabels": false, 941 | "thresholdMarkers": true 942 | }, 943 | "height": "", 944 | "id": 10, 945 | "interval": null, 946 | "links": [], 947 | "mappingType": 1, 948 | "mappingTypes": [ 949 | { 950 | "name": "value to text", 951 | "value": 1 952 | }, 953 | { 954 | "name": "range to text", 955 | "value": 2 956 | } 957 | ], 958 | "maxDataPoints": 100, 959 | "nullPointMode": "connected", 960 | "nullText": null, 961 | "postfix": "", 962 | "postfixFontSize": "50%", 963 | "prefix": "", 964 | "prefixFontSize": "50%", 965 | "rangeMaps": [ 966 | { 967 | "from": "null", 968 | "text": "N/A", 969 | "to": "null" 970 | } 971 | ], 972 | "span": 3, 973 | "sparkline": { 974 | "fillColor": "rgba(31, 118, 189, 0.18)", 975 | "full": false, 976 | "lineColor": "rgb(31, 120, 193)", 977 | "show": false 978 | }, 979 | "targets": [ 980 | { 981 | "refId": "A", 982 | "target": "$Server.jenkins.plugins.active" 983 | } 984 | ], 985 | "thresholds": "50,75", 986 | "title": "Active", 987 | "type": "singlestat", 988 | "valueFontSize": "80%", 989 | "valueMaps": [ 990 | { 991 | "op": "=", 992 | "text": "N/A", 993 | "value": "null" 994 | } 995 | ], 996 | "valueName": "avg" 997 | }, 998 | { 999 | "cacheTimeout": null, 1000 | "colorBackground": false, 1001 | "colorValue": true, 1002 | "colors": [ 1003 | "rgba(50, 172, 45, 0.97)", 1004 | "rgba(237, 129, 40, 0.89)", 1005 | "rgba(245, 54, 54, 0.9)" 1006 | ], 1007 | "datasource": "${DS_LOCALGRAPHITE}", 1008 | "editable": true, 1009 | "error": false, 1010 | "format": "none", 1011 | "gauge": { 1012 | "maxValue": 100, 1013 | "minValue": 0, 1014 | "show": false, 1015 | "thresholdLabels": false, 1016 | "thresholdMarkers": true 1017 | }, 1018 | "height": "", 1019 | "id": 11, 1020 | "interval": null, 1021 | "links": [], 1022 | "mappingType": 1, 1023 | "mappingTypes": [ 1024 | { 1025 | "name": "value to text", 1026 | "value": 1 1027 | }, 1028 | { 1029 | "name": "range to text", 1030 | "value": 2 1031 | } 1032 | ], 1033 | "maxDataPoints": 100, 1034 | "nullPointMode": "connected", 1035 | "nullText": null, 1036 | "postfix": "", 1037 | "postfixFontSize": "50%", 1038 | "prefix": "", 1039 | "prefixFontSize": "50%", 1040 | "rangeMaps": [ 1041 | { 1042 | "from": "null", 1043 | "text": "N/A", 1044 | "to": "null" 1045 | } 1046 | ], 1047 | "span": 3, 1048 | "sparkline": { 1049 | "fillColor": "rgba(31, 118, 189, 0.18)", 1050 | "full": false, 1051 | "lineColor": "rgb(31, 120, 193)", 1052 | "show": false 1053 | }, 1054 | "targets": [ 1055 | { 1056 | "refId": "A", 1057 | "target": "$Server.jenkins.plugins.withUpdate" 1058 | } 1059 | ], 1060 | "thresholds": "15,50", 1061 | "title": "Need Update", 1062 | "type": "singlestat", 1063 | "valueFontSize": "80%", 1064 | "valueMaps": [ 1065 | { 1066 | "op": "=", 1067 | "text": "N/A", 1068 | "value": "null" 1069 | } 1070 | ], 1071 | "valueName": "avg" 1072 | }, 1073 | { 1074 | "cacheTimeout": null, 1075 | "colorBackground": false, 1076 | "colorValue": true, 1077 | "colors": [ 1078 | "rgba(50, 172, 45, 0.97)", 1079 | "rgba(237, 129, 40, 0.89)", 1080 | "rgba(245, 157, 54, 0.9)" 1081 | ], 1082 | "datasource": "${DS_LOCALGRAPHITE}", 1083 | "editable": true, 1084 | "error": false, 1085 | "format": "none", 1086 | "gauge": { 1087 | "maxValue": 100, 1088 | "minValue": 0, 1089 | "show": false, 1090 | "thresholdLabels": false, 1091 | "thresholdMarkers": true 1092 | }, 1093 | "height": "", 1094 | "id": 12, 1095 | "interval": null, 1096 | "links": [], 1097 | "mappingType": 1, 1098 | "mappingTypes": [ 1099 | { 1100 | "name": "value to text", 1101 | "value": 1 1102 | }, 1103 | { 1104 | "name": "range to text", 1105 | "value": 2 1106 | } 1107 | ], 1108 | "maxDataPoints": 100, 1109 | "nullPointMode": "connected", 1110 | "nullText": null, 1111 | "postfix": "", 1112 | "postfixFontSize": "50%", 1113 | "prefix": "", 1114 | "prefixFontSize": "50%", 1115 | "rangeMaps": [ 1116 | { 1117 | "from": "null", 1118 | "text": "N/A", 1119 | "to": "null" 1120 | } 1121 | ], 1122 | "span": 3, 1123 | "sparkline": { 1124 | "fillColor": "rgba(31, 118, 189, 0.18)", 1125 | "full": false, 1126 | "lineColor": "rgb(31, 120, 193)", 1127 | "show": false 1128 | }, 1129 | "targets": [ 1130 | { 1131 | "refId": "A", 1132 | "target": "$Server.jenkins.plugins.inactive" 1133 | } 1134 | ], 1135 | "thresholds": "1,1", 1136 | "title": "Inactive", 1137 | "type": "singlestat", 1138 | "valueFontSize": "80%", 1139 | "valueMaps": [ 1140 | { 1141 | "op": "=", 1142 | "text": "N/A", 1143 | "value": "null" 1144 | } 1145 | ], 1146 | "valueName": "avg" 1147 | }, 1148 | { 1149 | "cacheTimeout": null, 1150 | "colorBackground": false, 1151 | "colorValue": true, 1152 | "colors": [ 1153 | "rgba(50, 172, 45, 0.97)", 1154 | "rgba(237, 129, 40, 0.89)", 1155 | "rgba(245, 54, 54, 0.9)" 1156 | ], 1157 | "datasource": "${DS_LOCALGRAPHITE}", 1158 | "editable": true, 1159 | "error": false, 1160 | "format": "none", 1161 | "gauge": { 1162 | "maxValue": 100, 1163 | "minValue": 0, 1164 | "show": false, 1165 | "thresholdLabels": false, 1166 | "thresholdMarkers": true 1167 | }, 1168 | "height": "", 1169 | "id": 13, 1170 | "interval": null, 1171 | "links": [], 1172 | "mappingType": 1, 1173 | "mappingTypes": [ 1174 | { 1175 | "name": "value to text", 1176 | "value": 1 1177 | }, 1178 | { 1179 | "name": "range to text", 1180 | "value": 2 1181 | } 1182 | ], 1183 | "maxDataPoints": 100, 1184 | "nullPointMode": "connected", 1185 | "nullText": null, 1186 | "postfix": "", 1187 | "postfixFontSize": "50%", 1188 | "prefix": "", 1189 | "prefixFontSize": "50%", 1190 | "rangeMaps": [ 1191 | { 1192 | "from": "null", 1193 | "text": "N/A", 1194 | "to": "null" 1195 | } 1196 | ], 1197 | "span": 3, 1198 | "sparkline": { 1199 | "fillColor": "rgba(31, 118, 189, 0.18)", 1200 | "full": false, 1201 | "lineColor": "rgb(180, 186, 191)", 1202 | "show": false 1203 | }, 1204 | "targets": [ 1205 | { 1206 | "refId": "A", 1207 | "target": "$Server.jenkins.plugins.failed" 1208 | } 1209 | ], 1210 | "thresholds": "1,1", 1211 | "title": "Failed", 1212 | "type": "singlestat", 1213 | "valueFontSize": "80%", 1214 | "valueMaps": [ 1215 | { 1216 | "op": "=", 1217 | "text": "N/A", 1218 | "value": "null" 1219 | } 1220 | ], 1221 | "valueName": "avg" 1222 | } 1223 | ], 1224 | "repeat": null, 1225 | "repeatIteration": null, 1226 | "repeatRowId": null, 1227 | "showTitle": true, 1228 | "title": "Plugin Statistics", 1229 | "titleSize": "h6" 1230 | }, 1231 | { 1232 | "collapse": false, 1233 | "height": "100px", 1234 | "panels": [ 1235 | { 1236 | "cacheTimeout": null, 1237 | "colorBackground": false, 1238 | "colorValue": true, 1239 | "colors": [ 1240 | "rgba(245, 54, 54, 0.9)", 1241 | "rgba(237, 129, 40, 0.89)", 1242 | "rgba(50, 172, 45, 0.97)" 1243 | ], 1244 | "datasource": "${DS_LOCALGRAPHITE}", 1245 | "editable": true, 1246 | "error": false, 1247 | "format": "none", 1248 | "gauge": { 1249 | "maxValue": 100, 1250 | "minValue": 0, 1251 | "show": false, 1252 | "thresholdLabels": false, 1253 | "thresholdMarkers": true 1254 | }, 1255 | "id": 17, 1256 | "interval": null, 1257 | "links": [], 1258 | "mappingType": 1, 1259 | "mappingTypes": [ 1260 | { 1261 | "name": "value to text", 1262 | "value": 1 1263 | }, 1264 | { 1265 | "name": "range to text", 1266 | "value": 2 1267 | } 1268 | ], 1269 | "maxDataPoints": 100, 1270 | "nullPointMode": "connected", 1271 | "nullText": null, 1272 | "postfix": "", 1273 | "postfixFontSize": "50%", 1274 | "prefix": "", 1275 | "prefixFontSize": "50%", 1276 | "rangeMaps": [ 1277 | { 1278 | "from": "null", 1279 | "text": "N/A", 1280 | "to": "null" 1281 | } 1282 | ], 1283 | "span": 2, 1284 | "sparkline": { 1285 | "fillColor": "rgba(148, 158, 166, 0)", 1286 | "full": false, 1287 | "lineColor": "rgb(28, 108, 174)", 1288 | "show": true 1289 | }, 1290 | "targets": [ 1291 | { 1292 | "refId": "A", 1293 | "target": "derivative(summarize($Server.jenkins.runs.total.count, '1h', 'avg'))" 1294 | } 1295 | ], 1296 | "thresholds": "5,15", 1297 | "title": "Jobs/Hr", 1298 | "type": "singlestat", 1299 | "valueFontSize": "80%", 1300 | "valueMaps": [ 1301 | { 1302 | "op": "=", 1303 | "text": "N/A", 1304 | "value": "null" 1305 | } 1306 | ], 1307 | "valueName": "current" 1308 | }, 1309 | { 1310 | "cacheTimeout": null, 1311 | "colorBackground": false, 1312 | "colorValue": true, 1313 | "colors": [ 1314 | "rgba(245, 54, 54, 0.9)", 1315 | "rgba(237, 129, 40, 0.89)", 1316 | "rgba(50, 172, 45, 0.97)" 1317 | ], 1318 | "datasource": "${DS_LOCALGRAPHITE}", 1319 | "decimals": 0, 1320 | "editable": true, 1321 | "error": false, 1322 | "format": "none", 1323 | "gauge": { 1324 | "maxValue": 100, 1325 | "minValue": 0, 1326 | "show": false, 1327 | "thresholdLabels": false, 1328 | "thresholdMarkers": true 1329 | }, 1330 | "id": 21, 1331 | "interval": null, 1332 | "links": [], 1333 | "mappingType": 1, 1334 | "mappingTypes": [ 1335 | { 1336 | "name": "value to text", 1337 | "value": 1 1338 | }, 1339 | { 1340 | "name": "range to text", 1341 | "value": 2 1342 | } 1343 | ], 1344 | "maxDataPoints": 100, 1345 | "nullPointMode": "connected", 1346 | "nullText": null, 1347 | "postfix": "", 1348 | "postfixFontSize": "50%", 1349 | "prefix": "", 1350 | "prefixFontSize": "50%", 1351 | "rangeMaps": [ 1352 | { 1353 | "from": "null", 1354 | "text": "N/A", 1355 | "to": "null" 1356 | } 1357 | ], 1358 | "span": 2, 1359 | "sparkline": { 1360 | "fillColor": "rgba(148, 158, 166, 0)", 1361 | "full": false, 1362 | "lineColor": "rgb(28, 108, 174)", 1363 | "show": false 1364 | }, 1365 | "targets": [ 1366 | { 1367 | "refId": "A", 1368 | "target": "$Server.jenkins.project.enabled.count.value" 1369 | } 1370 | ], 1371 | "thresholds": "0,0", 1372 | "title": "Enabled Jobs", 1373 | "type": "singlestat", 1374 | "valueFontSize": "80%", 1375 | "valueMaps": [ 1376 | { 1377 | "op": "=", 1378 | "text": "N/A", 1379 | "value": "null" 1380 | } 1381 | ], 1382 | "valueName": "current" 1383 | }, 1384 | { 1385 | "cacheTimeout": null, 1386 | "colorBackground": false, 1387 | "colorValue": true, 1388 | "colors": [ 1389 | "rgba(50, 172, 45, 0.97)", 1390 | "rgba(237, 129, 40, 0.89)", 1391 | "rgba(245, 54, 54, 0.9)" 1392 | ], 1393 | "datasource": "${DS_LOCALGRAPHITE}", 1394 | "decimals": 0, 1395 | "editable": true, 1396 | "error": false, 1397 | "format": "none", 1398 | "gauge": { 1399 | "maxValue": 100, 1400 | "minValue": 0, 1401 | "show": false, 1402 | "thresholdLabels": false, 1403 | "thresholdMarkers": true 1404 | }, 1405 | "id": 22, 1406 | "interval": null, 1407 | "links": [], 1408 | "mappingType": 1, 1409 | "mappingTypes": [ 1410 | { 1411 | "name": "value to text", 1412 | "value": 1 1413 | }, 1414 | { 1415 | "name": "range to text", 1416 | "value": 2 1417 | } 1418 | ], 1419 | "maxDataPoints": 100, 1420 | "nullPointMode": "connected", 1421 | "nullText": null, 1422 | "postfix": "", 1423 | "postfixFontSize": "50%", 1424 | "prefix": "", 1425 | "prefixFontSize": "50%", 1426 | "rangeMaps": [ 1427 | { 1428 | "from": "null", 1429 | "text": "N/A", 1430 | "to": "null" 1431 | } 1432 | ], 1433 | "span": 2, 1434 | "sparkline": { 1435 | "fillColor": "rgba(148, 158, 166, 0)", 1436 | "full": false, 1437 | "lineColor": "rgb(28, 108, 174)", 1438 | "show": false 1439 | }, 1440 | "targets": [ 1441 | { 1442 | "refId": "A", 1443 | "target": "$Server.jenkins.project.disabled.count.value" 1444 | } 1445 | ], 1446 | "thresholds": "0,0", 1447 | "title": "Disabled", 1448 | "type": "singlestat", 1449 | "valueFontSize": "80%", 1450 | "valueMaps": [ 1451 | { 1452 | "op": "=", 1453 | "text": "N/A", 1454 | "value": "null" 1455 | } 1456 | ], 1457 | "valueName": "current" 1458 | }, 1459 | { 1460 | "cacheTimeout": null, 1461 | "colorBackground": false, 1462 | "colorValue": true, 1463 | "colors": [ 1464 | "rgba(245, 54, 54, 0.9)", 1465 | "rgba(237, 129, 40, 0.89)", 1466 | "rgba(50, 172, 45, 0.97)" 1467 | ], 1468 | "datasource": "${DS_LOCALGRAPHITE}", 1469 | "decimals": 0, 1470 | "editable": true, 1471 | "error": false, 1472 | "format": "none", 1473 | "gauge": { 1474 | "maxValue": 100, 1475 | "minValue": 0, 1476 | "show": false, 1477 | "thresholdLabels": false, 1478 | "thresholdMarkers": true 1479 | }, 1480 | "id": 18, 1481 | "interval": null, 1482 | "links": [], 1483 | "mappingType": 1, 1484 | "mappingTypes": [ 1485 | { 1486 | "name": "value to text", 1487 | "value": 1 1488 | }, 1489 | { 1490 | "name": "range to text", 1491 | "value": 2 1492 | } 1493 | ], 1494 | "maxDataPoints": 100, 1495 | "nullPointMode": "connected", 1496 | "nullText": null, 1497 | "postfix": "", 1498 | "postfixFontSize": "50%", 1499 | "prefix": "", 1500 | "prefixFontSize": "50%", 1501 | "rangeMaps": [ 1502 | { 1503 | "from": "null", 1504 | "text": "N/A", 1505 | "to": "null" 1506 | } 1507 | ], 1508 | "span": 2, 1509 | "sparkline": { 1510 | "fillColor": "rgba(148, 158, 166, 0)", 1511 | "full": false, 1512 | "lineColor": "rgb(28, 108, 174)", 1513 | "show": false 1514 | }, 1515 | "targets": [ 1516 | { 1517 | "refId": "A", 1518 | "target": "$Server.jenkins.runs.total.count" 1519 | } 1520 | ], 1521 | "thresholds": "0,0", 1522 | "title": "Job Run Count", 1523 | "type": "singlestat", 1524 | "valueFontSize": "80%", 1525 | "valueMaps": [ 1526 | { 1527 | "op": "=", 1528 | "text": "N/A", 1529 | "value": "null" 1530 | } 1531 | ], 1532 | "valueName": "current" 1533 | }, 1534 | { 1535 | "cacheTimeout": null, 1536 | "colorBackground": false, 1537 | "colorValue": true, 1538 | "colors": [ 1539 | "rgba(245, 54, 54, 0.9)", 1540 | "rgba(237, 129, 40, 0.89)", 1541 | "rgba(50, 172, 45, 0.97)" 1542 | ], 1543 | "datasource": "${DS_LOCALGRAPHITE}", 1544 | "decimals": 2, 1545 | "editable": true, 1546 | "error": false, 1547 | "format": "ms", 1548 | "gauge": { 1549 | "maxValue": 100, 1550 | "minValue": 0, 1551 | "show": false, 1552 | "thresholdLabels": false, 1553 | "thresholdMarkers": true 1554 | }, 1555 | "id": 19, 1556 | "interval": null, 1557 | "links": [], 1558 | "mappingType": 1, 1559 | "mappingTypes": [ 1560 | { 1561 | "name": "value to text", 1562 | "value": 1 1563 | }, 1564 | { 1565 | "name": "range to text", 1566 | "value": 2 1567 | } 1568 | ], 1569 | "maxDataPoints": 100, 1570 | "nullPointMode": "connected", 1571 | "nullText": null, 1572 | "postfix": "", 1573 | "postfixFontSize": "50%", 1574 | "prefix": "", 1575 | "prefixFontSize": "50%", 1576 | "rangeMaps": [ 1577 | { 1578 | "from": "null", 1579 | "text": "N/A", 1580 | "to": "null" 1581 | } 1582 | ], 1583 | "span": 4, 1584 | "sparkline": { 1585 | "fillColor": "rgba(148, 158, 166, 0)", 1586 | "full": false, 1587 | "lineColor": "rgb(28, 108, 174)", 1588 | "show": false 1589 | }, 1590 | "targets": [ 1591 | { 1592 | "refId": "A", 1593 | "target": "$Server.vm.uptime.milliseconds" 1594 | } 1595 | ], 1596 | "thresholds": "0,0", 1597 | "title": "Jenkins Uptime", 1598 | "type": "singlestat", 1599 | "valueFontSize": "80%", 1600 | "valueMaps": [ 1601 | { 1602 | "op": "=", 1603 | "text": "N/A", 1604 | "value": "null" 1605 | } 1606 | ], 1607 | "valueName": "current" 1608 | } 1609 | ], 1610 | "repeat": null, 1611 | "repeatIteration": null, 1612 | "repeatRowId": null, 1613 | "showTitle": true, 1614 | "title": "Basic Stats", 1615 | "titleSize": "h6" 1616 | }, 1617 | { 1618 | "collapse": false, 1619 | "height": "250px", 1620 | "panels": [ 1621 | { 1622 | "aliasColors": {}, 1623 | "bars": false, 1624 | "datasource": "${DS_LOCALGRAPHITE}", 1625 | "editable": true, 1626 | "error": false, 1627 | "fill": 1, 1628 | "grid": {}, 1629 | "id": 25, 1630 | "legend": { 1631 | "avg": false, 1632 | "current": false, 1633 | "max": false, 1634 | "min": false, 1635 | "show": true, 1636 | "total": false, 1637 | "values": false 1638 | }, 1639 | "lines": true, 1640 | "linewidth": 2, 1641 | "links": [], 1642 | "nullPointMode": "connected", 1643 | "percentage": false, 1644 | "pointradius": 5, 1645 | "points": false, 1646 | "renderer": "flot", 1647 | "seriesOverrides": [], 1648 | "span": 6, 1649 | "stack": false, 1650 | "steppedLine": false, 1651 | "targets": [ 1652 | { 1653 | "refId": "A", 1654 | "target": "alias($Server.vm.cpu.load, 'CPU Load')" 1655 | } 1656 | ], 1657 | "thresholds": [], 1658 | "timeFrom": null, 1659 | "timeShift": null, 1660 | "title": "CPU Load (Jenkins)", 1661 | "tooltip": { 1662 | "shared": true, 1663 | "sort": 0, 1664 | "value_type": "cumulative" 1665 | }, 1666 | "type": "graph", 1667 | "xaxis": { 1668 | "mode": "time", 1669 | "name": null, 1670 | "show": true, 1671 | "values": [] 1672 | }, 1673 | "yaxes": [ 1674 | { 1675 | "format": "short", 1676 | "logBase": 1, 1677 | "max": null, 1678 | "min": null, 1679 | "show": true 1680 | }, 1681 | { 1682 | "format": "short", 1683 | "logBase": 1, 1684 | "max": null, 1685 | "min": null, 1686 | "show": true 1687 | } 1688 | ] 1689 | }, 1690 | { 1691 | "aliasColors": {}, 1692 | "bars": false, 1693 | "datasource": "${DS_LOCALGRAPHITE}", 1694 | "editable": true, 1695 | "error": false, 1696 | "fill": 1, 1697 | "grid": {}, 1698 | "id": 26, 1699 | "legend": { 1700 | "avg": false, 1701 | "current": false, 1702 | "max": false, 1703 | "min": false, 1704 | "show": true, 1705 | "total": false, 1706 | "values": false 1707 | }, 1708 | "lines": true, 1709 | "linewidth": 2, 1710 | "links": [], 1711 | "nullPointMode": "connected", 1712 | "percentage": false, 1713 | "pointradius": 5, 1714 | "points": false, 1715 | "renderer": "flot", 1716 | "seriesOverrides": [], 1717 | "span": 6, 1718 | "stack": false, 1719 | "steppedLine": false, 1720 | "targets": [ 1721 | { 1722 | "refId": "A", 1723 | "target": "$Server.http.activeRequests.count" 1724 | } 1725 | ], 1726 | "thresholds": [], 1727 | "timeFrom": null, 1728 | "timeShift": null, 1729 | "title": "HTTP Requests", 1730 | "tooltip": { 1731 | "shared": true, 1732 | "sort": 0, 1733 | "value_type": "cumulative" 1734 | }, 1735 | "type": "graph", 1736 | "xaxis": { 1737 | "mode": "time", 1738 | "name": null, 1739 | "show": true, 1740 | "values": [] 1741 | }, 1742 | "yaxes": [ 1743 | { 1744 | "format": "short", 1745 | "logBase": 1, 1746 | "max": null, 1747 | "min": null, 1748 | "show": true 1749 | }, 1750 | { 1751 | "format": "short", 1752 | "logBase": 1, 1753 | "max": null, 1754 | "min": null, 1755 | "show": true 1756 | } 1757 | ] 1758 | } 1759 | ], 1760 | "repeat": null, 1761 | "repeatIteration": null, 1762 | "repeatRowId": null, 1763 | "showTitle": false, 1764 | "title": "New row", 1765 | "titleSize": "h6" 1766 | } 1767 | ], 1768 | "schemaVersion": 14, 1769 | "style": "dark", 1770 | "tags": [], 1771 | "templating": { 1772 | "list": [ 1773 | { 1774 | "allFormat": "glob", 1775 | "allValue": null, 1776 | "current": {}, 1777 | "datasource": "${DS_LOCALGRAPHITE}", 1778 | "hide": 0, 1779 | "includeAll": false, 1780 | "label": null, 1781 | "multi": false, 1782 | "multiFormat": "glob", 1783 | "name": "Server", 1784 | "options": [], 1785 | "query": "*", 1786 | "refresh": 1, 1787 | "regex": "/.*jenkins.*/", 1788 | "sort": 0, 1789 | "tagValuesQuery": "", 1790 | "tags": [], 1791 | "tagsQuery": "", 1792 | "type": "query", 1793 | "useTags": false 1794 | } 1795 | ] 1796 | }, 1797 | "time": { 1798 | "from": "now-1h", 1799 | "to": "now" 1800 | }, 1801 | "timepicker": { 1802 | "now": true, 1803 | "refresh_intervals": [ 1804 | "5s", 1805 | "10s", 1806 | "30s", 1807 | "1m", 1808 | "5m", 1809 | "15m", 1810 | "30m", 1811 | "1h", 1812 | "2h", 1813 | "1d" 1814 | ], 1815 | "time_options": [ 1816 | "5m", 1817 | "15m", 1818 | "1h", 1819 | "6h", 1820 | "12h", 1821 | "24h", 1822 | "2d", 1823 | "7d", 1824 | "30d" 1825 | ] 1826 | }, 1827 | "timezone": "browser", 1828 | "title": "Jenkins Metrics", 1829 | "version": 3 1830 | } -------------------------------------------------------------------------------- /monitoring/README.md: -------------------------------------------------------------------------------- 1 | # Quick Start 2 | 3 | Make sure you have Docker for Mac/Windows or Docker-toolbox installed. 4 | 5 | 1. Sync the repo locally 6 | 2. `cd monitoring` 7 | 3. `make build` 8 | 4. `make run` 9 | 10 | This will start a Graphite DB docker container, a Grafana docker ocntainer and a data-volume that keeps data from both Graphite and Grafana. 11 | Once these are running you have a few more Jenkins Configuration steps: 12 | 13 | 1. Install the "metrics-plugin" for Jenkins 14 | 2. Install the "Metrics Graphite Reporting Plugin" for Jenkins 15 | 3. After restart Jenkins go to the jenkins configure page 16 | 4. Find "Graphite metrics reporting" 17 | 5. Set "hostname" to your local docker host IP (where Graphite is running) 18 | 6. Set the "port" to 2003 19 | 7. Set the "prefix" to "jenkinslocal" 20 | 8. Save config 21 | 22 | Jenkins will now start pushing metrics to Graphite. This will take up to 30-45 minutes for all metrics to show up. While waiting, set up a grafana data source and dashboard! 23 | 24 | ## Data Source 25 | 26 | 1. Point your browser to: http://dockerhostip:3000 27 | 2. On the Grafana login page, login as "admin/admin" 28 | 3. Go to "Datasources" (http://dockerhostip:3000/datasources) 29 | 4. Configure a new data source 30 | 5. Set the "type" to "Graphite" 31 | 6. Set the name to "LocalGraphite" 32 | 7. Set the Url to "http://dockerhostip:8080" 33 | 8. Click "Save & Test" 34 | 35 | ## Import dashboard 36 | 37 | I have a pre-built dashboard that should capture a lot of useful things about your jenkins server 38 | 39 | 1. Go to the Grafana home page (http://dockerhostip:3000) 40 | 2. Click on "Home" and then select "Import" 41 | 3. Choose "Upload .json file" 42 | 4. Pick the "JenkinsMetrics.json" file in the monitoring folder 43 | 5. Select "LocalGraphite" as the data source 44 | 45 | You should now have a dashboard monitoring Jenkins good to go. Please keep in mind it takes some time for the Graphite Metrics plugin to send data to 46 | graphite and for the graphite to show up. 47 | 48 | 49 | -------------------------------------------------------------------------------- /monitoring/data/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | MAINTAINER Maxfield Stewart 3 | 4 | RUN mkdir /var/lib/grafana 5 | RUN mkdir /opt/graphite 6 | RUN mkdir /opt/graphite/storage 7 | 8 | VOLUME ["/var/lib/grafana","/opt/graphite/storage"] 9 | 10 | CMD ["echo", "Data container for Grafana"] -------------------------------------------------------------------------------- /monitoring/docker-compose.yml: -------------------------------------------------------------------------------- 1 | data: 2 | build: data 3 | grafana: 4 | image: grafana/grafana:4.2.0 5 | volumes_from: 6 | - data 7 | ports: 8 | - "3000:3000" 9 | graphite: 10 | build: graphite 11 | volumes_from: 12 | - data 13 | ports: 14 | - "2003:2003" 15 | - "8125:8125/udp" 16 | - "8126:8126" 17 | - "8080:80" 18 | 19 | -------------------------------------------------------------------------------- /monitoring/graphite/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM hopsoft/graphite-statsd:latest 2 | MAINTAINER Maxfield Stewart 3 | 4 | # We want to import our own storage-schema so we can control retention values 5 | COPY storage-schemas.conf /opt/graphite/conf/storage-schemas.conf 6 | 7 | -------------------------------------------------------------------------------- /monitoring/graphite/storage-schemas.conf: -------------------------------------------------------------------------------- 1 | # Schema definitions for Whisper files. Entries are scanned in order, 2 | # and first match wins. This file is scanned for changes every 60 seconds. 3 | # 4 | # [name] 5 | # pattern = regex 6 | # retentions = timePerPoint:timeToStore, timePerPoint:timeToStore, ... 7 | 8 | # Carbon's internal metrics. This entry should match what is specified in 9 | # CARBON_METRIC_PREFIX and CARBON_METRIC_INTERVAL settings 10 | 11 | [carbon] 12 | pattern = ^carbon\. 13 | retentions = 10s:6h,1min:90d 14 | 15 | # Jenkins metrics assumes nodes are more permanent than the docker style ones 16 | # So we filter out the node data quickly that way they don't build up over time 17 | # (Each docker node has a unique name that clogs the metrics in graphite) 18 | [jenkins] 19 | pattern = ^localjenkins\.*\.node$ 20 | retentions = 10s:4h 21 | 22 | [default_1min_for_1day] 23 | pattern = .* 24 | retentions = 10s:4h,1min:12h,5min:1d,10min:30d -------------------------------------------------------------------------------- /monitoring/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker-compose -p monitoring build 3 | @docker-compose -p monitoring pull grafana graphite 4 | run: 5 | @docker-compose -p monitoring up -d grafana graphite data 6 | stop: 7 | @docker-compose -p monitoring stop 8 | clean: stop 9 | @docker-compose -p monitoring rm grafana graphite 10 | clean-data: clean 11 | @docker-compose -p monitoring rm -v data 12 | clean-images: 13 | @docker rmi `docker images -q -f "dangling=true"` -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | # Utility Scripts 2 | 3 | This folder contains scripts for helping to maintain your development environment. If you decide to install additional plugins, set up credentials or or change any configuration the scripts in this directory will help you make things permanently applied to your base images. 4 | 5 | # Updating Jenkins Configuration 6 | 7 | If you change settings in the jenkins master config panel or make build jobs you'd prefer to always be available even if you blow away your data container just use the `getExport.sh` script as follows: 8 | 9 | 1. Go to the /scripts folder 10 | 2. run the getExport.sh script 11 | 12 | This script relies on the `configIncludes.txt` file to determine what jenkins configuration to extract. You may have to add additional files depending on the plugin/configs you want to save. That said the script extracts all current job configuration and jenkins settings and places them in the `jenkinsexport.tar.gz` file in the "jenkins-data" directory. To use it, just wipe your jenkins images (make clean-data) and rebuild (make build) 13 | 14 | # Updating the default plugins 15 | 16 | You may want to add additional plugins to your default install. The plugins built in by default are in `jenkins-master/plugins.txt` you could just hand edit that file and add the plugins you want. Alternatively, you can install the plugins to your local jenkins instance. Then do the following: 17 | 18 | 1. Go to: http://yourjenkinsip/script 19 | 2. Cut and paste the `listPlugins.groovy` in this folder into the script window and run it 20 | 3. Cut and paste the output of that run into the `plugins.txt` file in `jenkins-master/plugins.txt`. 21 | 4. Rebuild your jenkins environment (don't forget to clean your data file with `make clean-data`) 22 | 23 | # Exporting and saving your credentials 24 | 25 | Please Note: Be wary using this on a production jenkins instance, while the credentials are encrypted this captures and stores everything jenkins needs to decrypt them, which means anything a malicious intruder would also need to decrypt them. Use with caution, but provided here incase you want to set up default creds for development/practice use and s hare them. 26 | 27 | After setting your credentials in Jenkins how you want them do the following: 28 | 29 | 1. Go to the /scripts folder 30 | 2. Run `getSecrets.sh` 31 | 3. This will create a "jenkinssecrets.tar.gz" file 32 | 33 | You can now, every time you rebuild jenkins, just run the `setSecrets.sh` to reimport your secrets (restart jenkins after) OR if you want to make them permanent: 34 | 35 | 4. Copy `jenkinssecrets.tar.gz` over the file `jenkins-data\jenkinsdefaultsecrets.tar.gz` 36 | 5. Rebuild your jenkins environment (remember to clean data with make clean-data) 37 | 38 | -------------------------------------------------------------------------------- /scripts/configIncludes.txt: -------------------------------------------------------------------------------- 1 | /var/jenkins_home/config.xml 2 | /var/jenkins_home/scriptApproval.xml 3 | /var/jenkins_home/scriptler 4 | /var/jenkins_home/hudson.tasks.Mailer.xml 5 | /var/jenkins_home/org.jenkinsci.plugins.pipeline.modeldefinition.config.GlobalConfig.xml 6 | /var/jenkins_home/org.jenkinsci.plugins.workflow.libs.GlobalLibraries.xml 7 | /var/jenkins_home/jenkins.model.JenkinsLocationConfiguration.xml 8 | /var/jenkins_home/jenkins.security.UpdateSiteWarningsConfiguration.xml 9 | /var/jenkins_home/org.jenkinsci.plugins.github_branch_source.GitHubConfiguration.xml 10 | -------------------------------------------------------------------------------- /scripts/getExport.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker cp configIncludes.txt jenkins_master_1:/tmp/configIncludes.txt 3 | docker exec jenkins_master_1 bash -c "tar -czvf /tmp/jenkinsexport.tar.gz -T /tmp/configIncludes.txt" 4 | docker cp jenkins_master_1:/tmp/jenkinsexport.tar.gz ../jenkins/jenkins-master/jenkinsexport.tar.gz 5 | 6 | # docker cp can't do pattern matching, so we grab everything and then delete 7 | # the stuff we don't want 8 | rm -rf ../jenkins/jenkins-master/jobs 9 | docker cp jenkins_master_1:/var/jenkins_home/jobs/ ../jenkins/jenkins-master/ 10 | find ../jenkins/jenkins-master/jobs ! -type directory ! -name 'config.xml' -exec rm {} \; 11 | -------------------------------------------------------------------------------- /scripts/getSecrets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker cp secretsIncludes.txt jenkins2_master_1:/tmp/secretsIncludes.txt 3 | docker exec --user root jenkins2_master_1 bash -c "tar -czvf /tmp/jenkinssecrets.tar.gz -T /tmp/secretsIncludes.txt" 4 | docker cp jenkins_master_1:/tmp/jenkinssecrets.tar.gz jenkinssecrets.tar.gz -------------------------------------------------------------------------------- /scripts/listPlugins.groovy: -------------------------------------------------------------------------------- 1 | // If you need to determine which plugins you're Jenkins instance requires, use this workflow: 2 | // 3 | // 1. Start your existing Jenkins instance 4 | // 2. Use the Plugin Manager in "Configure Jenkins" to install needed plugins and resolve dependencies 5 | // 3. Run this script in the System Groovy Console with the 'Groovy' plugin 6 | // 4. Replace the plugins.txt file contexts with the resulting output 7 | 8 | def plugins = new ArrayList(Jenkins.instance.pluginManager.plugins).sort() 9 | 10 | plugins.each() { plugin -> 11 | println plugin.getShortName() + " " + plugin.getVersion() 12 | } 13 | 14 | //println "\nPlugin Count: " + plugins.size() 15 | 16 | // Print one last time so the output isn't cluttered with .each()'s return of the list 17 | println() -------------------------------------------------------------------------------- /scripts/secretsIncludes.txt: -------------------------------------------------------------------------------- 1 | /var/jenkins_home/credentials.xml 2 | /var/jenkins_home/secrets 3 | /var/jenkins_home/secret.key 4 | /var/jenkins_home/secret.key.not-so-secret 5 | /var/jenkins_home/identity.key.enc -------------------------------------------------------------------------------- /scripts/setSecrets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker cp jenkinssecrets.tar.gz jenkins_master_1:/tmp/jenkinssecrets.tar.gz 3 | docker exec jenkins_master_1 tar -xvf /tmp/jenkinssecrets.tar.gz -------------------------------------------------------------------------------- /tutorial_01/README.md: -------------------------------------------------------------------------------- 1 | The tutorial for this makefile can be found here: http://live-rg-engineering.pantheon.io/news/putting-jenkins-docker-container -------------------------------------------------------------------------------- /tutorial_01/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker pull jenkins/jenkins:2.112 3 | run: 4 | @docker run -p 8080:8080 --name=jenkins-master -d --env JAVA_OPTS="-Xmx8192m" --env JENKINS_OPTS="--handlerCountMax=300" jenkins/jenkins:2.112 5 | start: 6 | @docker start jenkins-master 7 | stop: 8 | @docker stop jenkins-master 9 | clean: stop 10 | @docker rm -v jenkins-master 11 | -------------------------------------------------------------------------------- /tutorial_02/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkins/jenkins:2.112 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Create Jenkins Log Folder 5 | USER root 6 | RUN mkdir /var/log/jenkins 7 | RUN chown -R jenkins:jenkins /var/log/jenkins 8 | USER jenkins 9 | 10 | # Set default options 11 | ENV JAVA_OPTS="-Xmx8192m" 12 | ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log" 13 | -------------------------------------------------------------------------------- /tutorial_02/README.md: -------------------------------------------------------------------------------- 1 | The tutorial for these files can be found here: http://live-rg-engineering.pantheon.io/news/putting-jenkins-docker-container -------------------------------------------------------------------------------- /tutorial_02/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker build -t myjenkins . 3 | run: 4 | @docker run -p 8080:8080 -p 50000:50000 --name=jenkins-master -d myjenkins 5 | start: 6 | @docker start jenkins-master 7 | stop: 8 | @docker stop jenkins-master 9 | clean: stop 10 | @docker rm -v jenkins-master 11 | -------------------------------------------------------------------------------- /tutorial_03/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkins/jenkins:2.112 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Prep Jenkins Directories 5 | USER root 6 | RUN mkdir /var/log/jenkins 7 | RUN mkdir /var/cache/jenkins 8 | RUN chown -R jenkins:jenkins /var/log/jenkins 9 | RUN chown -R jenkins:jenkins /var/cache/jenkins 10 | USER jenkins 11 | 12 | # Set Defaults 13 | ENV JAVA_OPTS="-Xmx8192m" 14 | ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" 15 | -------------------------------------------------------------------------------- /tutorial_03/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker build -t myjenkins . 3 | create-data: 4 | @docker volume create jenkins-log 5 | @docker volume create jenkins-data 6 | run: create-data 7 | @docker run -p 8080:8080 -p 50000:50000 --name=jenkins-master --mount source=jenkins-log,target=/var/log/jenkins --mount source=jenkins-data,target=/var/jenkins_home -d myjenkins 8 | stop: 9 | -docker stop jenkins-master 10 | clean: stop 11 | -docker rm jenkins-master 12 | clean-data: clean 13 | -docker volume rm jenkins-log 14 | -docker volume rm jenkins-data 15 | -------------------------------------------------------------------------------- /tutorial_04/jenkins-master/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkins/jenkins:2.112 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Prep Jenkins Directories 5 | USER root 6 | RUN mkdir /var/log/jenkins 7 | RUN mkdir /var/cache/jenkins 8 | RUN chown -R jenkins:jenkins /var/log/jenkins 9 | RUN chown -R jenkins:jenkins /var/cache/jenkins 10 | USER jenkins 11 | 12 | # Set Defaults 13 | ENV JAVA_OPTS="-Xmx8192m" 14 | ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" 15 | -------------------------------------------------------------------------------- /tutorial_04/jenkins-nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Install NGINX 5 | RUN yum -y update; yum clean all 6 | RUN yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm; yum -y makecache 7 | RUN yum -y install nginx-1.10.1 8 | 9 | # Remove default files we don't need 10 | RUN rm /etc/nginx/conf.d/default.conf 11 | 12 | # Add default configuration 13 | COPY conf/jenkins.conf /etc/nginx/conf.d/jenkins.conf 14 | COPY conf/nginx.conf /etc/nginx/nginx.conf 15 | 16 | EXPOSE 80 17 | 18 | CMD ["nginx"] -------------------------------------------------------------------------------- /tutorial_04/jenkins-nginx/conf/jenkins.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name ""; 4 | 5 | access_log off; 6 | 7 | location / { 8 | proxy_pass http://jenkins-master:8080; 9 | 10 | proxy_set_header Host $host; 11 | proxy_set_header X-Real-IP $remote_addr; 12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 13 | proxy_set_header X-Forwarded-Proto http; 14 | proxy_max_temp_file_size 0; 15 | 16 | proxy_connect_timeout 150; 17 | proxy_send_timeout 100; 18 | proxy_read_timeout 100; 19 | 20 | proxy_buffer_size 8k; 21 | proxy_buffers 4 32k; 22 | proxy_busy_buffers_size 64k; 23 | proxy_temp_file_write_size 64k; 24 | 25 | 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /tutorial_04/jenkins-nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | user nginx; 3 | worker_processes 2; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | use epoll; 12 | accept_mutex off; 13 | } 14 | 15 | 16 | http { 17 | include /etc/nginx/mime.types; 18 | proxy_set_header X-Real-IP $remote_addr; 19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | 21 | default_type application/octet-stream; 22 | 23 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 24 | '$status $body_bytes_sent "$http_referer" ' 25 | '"$http_user_agent" "$http_x_forwarded_for"'; 26 | 27 | access_log /var/log/nginx/access.log main; 28 | 29 | sendfile on; 30 | #tcp_nopush on; 31 | 32 | keepalive_timeout 65; 33 | 34 | client_max_body_size 300m; 35 | client_body_buffer_size 128k; 36 | 37 | gzip on; 38 | gzip_http_version 1.0; 39 | gzip_comp_level 6; 40 | gzip_min_length 0; 41 | gzip_buffers 16 8k; 42 | gzip_proxied any; 43 | gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json; 44 | gzip_disable "MSIE [1-6]\."; 45 | gzip_vary on; 46 | 47 | include /etc/nginx/conf.d/*.conf; 48 | } 49 | -------------------------------------------------------------------------------- /tutorial_04/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker build -t myjenkins jenkins-master/. 3 | @docker build -t myjenkinsnginx jenkins-nginx/. 4 | create-network: 5 | -docker network create --driver bridge jenkins-net 6 | create-data: 7 | @docker volume create jenkins-data 8 | @docker volume create jenkins-log 9 | run: create-network create-data 10 | @docker run -p 50000:50000 --name=jenkins-master --network jenkins-net --mount source=jenkins-log,target=/var/log/jenkins --mount source=jenkins-data,target=/var/jenkins_home -d myjenkins 11 | @docker run -p 80:80 --name=jenkins-nginx --network jenkins-net -d myjenkinsnginx 12 | stop: 13 | -docker stop jenkins-master 14 | -docker stop jenkins-nginx 15 | clean: stop 16 | -docker rm jenkins-master 17 | -docker rm jenkins-nginx 18 | clean-data: clean 19 | -docker volume rm jenkins-data 20 | -docker volume rm jenkins-log 21 | clean-network: clean 22 | -docker network rm jenkins-net 23 | clean-images: 24 | @docker rmi `docker images -q -f "dangling=true"` 25 | 26 | -------------------------------------------------------------------------------- /tutorial_05/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | master: 4 | build: ./jenkins-master 5 | ports: 6 | - "50000:50000" 7 | volumes: 8 | - jenkins-log:/var/log/jenkins 9 | - jenkins-data:/var/jenkins_home 10 | networks: 11 | - jenkins-net 12 | nginx: 13 | build: ./jenkins-nginx 14 | ports: 15 | - "80:80" 16 | networks: 17 | - jenkins-net 18 | volumes: 19 | jenkins-data: 20 | jenkins-log: 21 | networks: 22 | jenkins-net: 23 | 24 | -------------------------------------------------------------------------------- /tutorial_05/jenkins-master/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkins/jenkins:2.112 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Prep Jenkins Directories 5 | USER root 6 | RUN mkdir /var/log/jenkins 7 | RUN mkdir /var/cache/jenkins 8 | RUN chown -R jenkins:jenkins /var/log/jenkins 9 | RUN chown -R jenkins:jenkins /var/cache/jenkins 10 | USER jenkins 11 | 12 | # Set Defaults 13 | ENV JAVA_OPTS="-Xmx8192m" 14 | ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" 15 | -------------------------------------------------------------------------------- /tutorial_05/jenkins-master/plugins.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tutorial_05/jenkins-nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Install NGINX 5 | RUN yum -y update; yum clean all 6 | RUN yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm; yum -y makecache 7 | RUN yum -y install nginx-1.10.1 8 | 9 | # Remove default files we don't need 10 | RUN rm /etc/nginx/conf.d/default.conf 11 | 12 | # Add default configuration 13 | COPY conf/jenkins.conf /etc/nginx/conf.d/jenkins.conf 14 | COPY conf/nginx.conf /etc/nginx/nginx.conf 15 | 16 | EXPOSE 80 17 | 18 | CMD ["nginx"] -------------------------------------------------------------------------------- /tutorial_05/jenkins-nginx/conf/jenkins.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name ""; 4 | 5 | access_log off; 6 | 7 | location / { 8 | proxy_pass http://jenkins_master_1:8080; 9 | 10 | proxy_set_header Host $host; 11 | proxy_set_header X-Real-IP $remote_addr; 12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 13 | proxy_set_header X-Forwarded-Proto http; 14 | proxy_max_temp_file_size 0; 15 | 16 | proxy_connect_timeout 150; 17 | proxy_send_timeout 100; 18 | proxy_read_timeout 100; 19 | 20 | proxy_buffer_size 8k; 21 | proxy_buffers 4 32k; 22 | proxy_busy_buffers_size 64k; 23 | proxy_temp_file_write_size 64k; 24 | 25 | 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /tutorial_05/jenkins-nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | user nginx; 3 | worker_processes 2; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | use epoll; 12 | accept_mutex off; 13 | } 14 | 15 | 16 | http { 17 | include /etc/nginx/mime.types; 18 | proxy_set_header X-Real-IP $remote_addr; 19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | 21 | default_type application/octet-stream; 22 | 23 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 24 | '$status $body_bytes_sent "$http_referer" ' 25 | '"$http_user_agent" "$http_x_forwarded_for"'; 26 | 27 | access_log /var/log/nginx/access.log main; 28 | 29 | sendfile on; 30 | #tcp_nopush on; 31 | 32 | keepalive_timeout 65; 33 | 34 | client_max_body_size 300m; 35 | client_body_buffer_size 128k; 36 | 37 | gzip on; 38 | gzip_http_version 1.0; 39 | gzip_comp_level 6; 40 | gzip_min_length 0; 41 | gzip_buffers 16 8k; 42 | gzip_proxied any; 43 | gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json; 44 | gzip_disable "MSIE [1-6]\."; 45 | gzip_vary on; 46 | 47 | include /etc/nginx/conf.d/*.conf; 48 | } 49 | -------------------------------------------------------------------------------- /tutorial_05/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker-compose -p jenkins build 3 | run: 4 | @docker-compose -p jenkins up -d 5 | stop: 6 | @docker-compose -p jenkins down 7 | clean-data: 8 | @docker-compose -p jenkins down -v 9 | clean-images: 10 | @docker rmi `docker images -q -f "dangling=true"` 11 | 12 | -------------------------------------------------------------------------------- /tutorial_06/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | master: 4 | build: ./jenkins-master 5 | ports: 6 | - "50000:50000" 7 | volumes: 8 | - jenkins-log:/var/log/jenkins 9 | - jenkins-data:/var/jenkins_home 10 | networks: 11 | - jenkins-net 12 | nginx: 13 | build: ./jenkins-nginx 14 | ports: 15 | - "80:80" 16 | networks: 17 | - jenkins-net 18 | volumes: 19 | jenkins-data: 20 | jenkins-log: 21 | networks: 22 | jenkins-net: 23 | -------------------------------------------------------------------------------- /tutorial_06/jenkins-master/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | ENV LANG C.UTF-8 5 | ENV JAVA_VERSION 8u162 6 | ENV JAVA_DEBIAN_VERSION 8u162-b12-1~deb9u1 7 | 8 | # see https://bugs.debian.org/775775 9 | # and https://github.com/docker-library/java/issues/19#issuecomment-70546872 10 | ENV CA_CERTIFICATES_JAVA_VERSION 20170531+nmu1 11 | 12 | RUN apt-get update \ 13 | && apt-get install -y --no-install-recommends \ 14 | wget \ 15 | curl \ 16 | ca-certificates \ 17 | zip \ 18 | openssh-client \ 19 | unzip \ 20 | openjdk-8-jdk="$JAVA_DEBIAN_VERSION" \ 21 | ca-certificates-java="$CA_CERTIFICATES_JAVA_VERSION" \ 22 | && rm -rf /var/lib/apt/lists/* 23 | 24 | RUN /var/lib/dpkg/info/ca-certificates-java.postinst configure 25 | 26 | ARG user=jenkins 27 | ARG group=jenkins 28 | ARG uid=1000 29 | ARG gid=1000 30 | ARG http_port=8080 31 | ARG agent_port=50000 32 | ARG JENKINS_VERSION=2.112 33 | ARG TINI_VERSION=v0.17.0 34 | 35 | # jenkins.war checksum, download will be validated using it 36 | ARG JENKINS_SHA=085f597edeb0d49d54d7653f3742ba31ed72b8a1a2b053d2eb23fd806c6a5393 37 | 38 | # Can be used to customize where jenkins.war get downloaded from 39 | ARG JENKINS_URL=https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/${JENKINS_VERSION}/jenkins-war-${JENKINS_VERSION}.war 40 | 41 | ENV JENKINS_VERSION ${JENKINS_VERSION} 42 | ENV JENKINS_HOME /var/jenkins_home 43 | ENV JENKINS_SLAVE_AGENT_PORT ${agent_port} 44 | ENV JENKINS_UC https://updates.jenkins.io 45 | ENV JENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimental 46 | ENV JAVA_OPTS="-Xmx8192m" 47 | ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" 48 | ENV COPY_REFERENCE_FILE_LOG $JENKINS_HOME/copy_reference_file.log 49 | 50 | # Use tini as subreaper in Docker container to adopt zombie processes 51 | RUN curl -fsSL https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static-$(dpkg --print-architecture) -o /sbin/tini \ 52 | && chmod +x /sbin/tini 53 | 54 | # Jenkins is run with user `jenkins`, uid = 1000 55 | # If you bind mount a volume from the host or a data container, 56 | # ensure you use the same uid 57 | RUN groupadd -g ${gid} ${group} \ 58 | && useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user} 59 | 60 | # Jenkins home directory is a volume, so configuration and build history 61 | # can be persisted and survive image upgrades 62 | VOLUME /var/jenkins_home 63 | 64 | # `/usr/share/jenkins/ref/` contains all reference configuration we want 65 | # to set on a fresh new installation. Use it to bundle additional plugins 66 | # or config file with your custom jenkins Docker image. 67 | RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d 68 | 69 | # could use ADD but this one does not check Last-Modified header neither does it allow to control checksum 70 | # see https://github.com/docker/docker/issues/8331 71 | RUN curl -fsSL ${JENKINS_URL} -o /usr/share/jenkins/jenkins.war \ 72 | && echo "${JENKINS_SHA} /usr/share/jenkins/jenkins.war" | sha256sum -c - 73 | 74 | RUN chown -R ${user} "$JENKINS_HOME" /usr/share/jenkins/ref 75 | RUN mkdir /var/log/jenkins 76 | RUN mkdir /var/cache/jenkins 77 | RUN chown -R ${user}:${user} /var/log/jenkins 78 | RUN chown -R ${user}:${user} /var/cache/jenkins 79 | 80 | # for main web and slave agents: 81 | EXPOSE ${http_port} 82 | EXPOSE ${agent_port} 83 | 84 | # Copy in local config files 85 | COPY init.groovy /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy 86 | COPY jenkins-support /usr/local/bin/jenkins-support 87 | COPY plugins.sh /usr/local/bin/plugins.sh 88 | COPY jenkins.sh /usr/local/bin/jenkins.sh 89 | COPY install-plugins.sh /usr/local/bin/install-plugins.sh 90 | RUN chmod +x /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy \ 91 | && chmod +x /usr/local/bin/jenkins-support \ 92 | && chmod +x /usr/local/bin/plugins.sh \ 93 | && chmod +x /usr/local/bin/jenkins.sh \ 94 | && chmod +x /usr/local/bin/install-plugins.sh 95 | 96 | USER ${user} 97 | 98 | ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/jenkins.sh"] 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /tutorial_06/jenkins-master/Dockerfile-Centos7: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | RUN yum makecache \ 5 | && yum update -y \ 6 | && yum install -y \ 7 | wget \ 8 | zip \ 9 | openssh-client \ 10 | unzip \ 11 | java-1.8.0-openjdk \ 12 | && yum clean all 13 | 14 | ARG user=jenkins 15 | ARG group=jenkins 16 | ARG uid=1000 17 | ARG gid=1000 18 | ARG http_port=8080 19 | ARG agent_port=50000 20 | ARG JENKINS_VERSION=2.112 21 | ARG TINI_VERSION=v0.17.0 22 | 23 | # jenkins.war checksum, download will be validated using it 24 | ARG JENKINS_SHA=085f597edeb0d49d54d7653f3742ba31ed72b8a1a2b053d2eb23fd806c6a5393 25 | 26 | # Can be used to customize where jenkins.war get downloaded from 27 | ARG JENKINS_URL=https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/${JENKINS_VERSION}/jenkins-war-${JENKINS_VERSION}.war 28 | 29 | ENV JENKINS_VERSION ${JENKINS_VERSION} 30 | ENV JENKINS_HOME /var/jenkins_home 31 | ENV JENKINS_SLAVE_AGENT_PORT ${agent_port} 32 | ENV JENKINS_UC https://updates.jenkins.io 33 | ENV JENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimental 34 | ENV JAVA_OPTS="-Xmx8192m" 35 | ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" 36 | ENV COPY_REFERENCE_FILE_LOG $JENKINS_HOME/copy_reference_file.log 37 | 38 | # Use tini as subreaper in Docker container to adopt zombie processes 39 | ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /bin/tini 40 | RUN chmod +x /bin/tini 41 | 42 | # Jenkins is run with user `jenkins`, uid = 1000 43 | # If you bind mount a volume from the host or a data container, 44 | # ensure you use the same uid 45 | RUN groupadd -g ${gid} ${group} \ 46 | && useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user} 47 | 48 | # Jenkins home directory is a volume, so configuration and build history 49 | # can be persisted and survive image upgrades 50 | VOLUME /var/jenkins_home 51 | 52 | # `/usr/share/jenkins/ref/` contains all reference configuration we want 53 | # to set on a fresh new installation. Use it to bundle additional plugins 54 | # or config file with your custom jenkins Docker image. 55 | RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d 56 | 57 | # Install Jenkins 58 | # could use ADD but this one does not check Last-Modified header neither does it allow to control checksum 59 | # see https://github.com/docker/docker/issues/8331 60 | RUN curl -fsSL ${JENKINS_URL} -o /usr/share/jenkins/jenkins.war \ 61 | && echo "${JENKINS_SHA} /usr/share/jenkins/jenkins.war" | sha256sum -c - 62 | 63 | # Prep Jenkins Directories 64 | RUN chown -R ${user} "$JENKINS_HOME" /usr/share/jenkins/ref 65 | RUN mkdir /var/log/jenkins 66 | RUN mkdir /var/cache/jenkins 67 | RUN chown -R ${user}:${user} /var/log/jenkins 68 | RUN chown -R ${user}:${user} /var/cache/jenkins 69 | 70 | # Expose Ports for web and slave agents 71 | EXPOSE ${http_port} 72 | EXPOSE ${agent_port} 73 | 74 | # Copy in local config files 75 | COPY init.groovy /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy 76 | COPY jenkins-support /usr/local/bin/jenkins-support 77 | COPY plugins.sh /usr/local/bin/plugins.sh 78 | COPY jenkins.sh /usr/local/bin/jenkins.sh 79 | COPY install-plugins.sh /usr/local/bin/install-plugins.sh 80 | RUN chmod +x /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy \ 81 | && chmod +x /usr/local/bin/jenkins-support \ 82 | && chmod +x /usr/local/bin/plugins.sh \ 83 | && chmod +x /usr/local/bin/jenkins.sh \ 84 | && chmod +x /usr/local/bin/install-plugins.sh 85 | 86 | # Switch to the jenkins user 87 | USER ${user} 88 | 89 | # Tini as the entry point to manage zombie processes 90 | ENTRYPOINT ["/bin/tini", "--", "/usr/local/bin/jenkins.sh"] 91 | 92 | -------------------------------------------------------------------------------- /tutorial_06/jenkins-master/init.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.*; 2 | import jenkins.model.*; 3 | 4 | 5 | Thread.start { 6 | sleep 10000 7 | println "--> setting agent port for jnlp" 8 | def env = System.getenv() 9 | int port = env['JENKINS_SLAVE_AGENT_PORT'].toInteger() 10 | Jenkins.instance.setSlaveAgentPort(port) 11 | println "--> setting agent port for jnlp... done" 12 | } 13 | -------------------------------------------------------------------------------- /tutorial_06/jenkins-master/install-plugins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | # Resolve dependencies and download plugins given on the command line 4 | # 5 | # FROM jenkins 6 | # RUN install-plugins.sh docker-slaves github-branch-source 7 | 8 | set -o pipefail 9 | 10 | REF_DIR=${REF:-/usr/share/jenkins/ref/plugins} 11 | FAILED="$REF_DIR/failed-plugins.txt" 12 | 13 | . /usr/local/bin/jenkins-support 14 | 15 | getLockFile() { 16 | printf '%s' "$REF_DIR/${1}.lock" 17 | } 18 | 19 | getArchiveFilename() { 20 | printf '%s' "$REF_DIR/${1}.jpi" 21 | } 22 | 23 | download() { 24 | local plugin originalPlugin version lock ignoreLockFile 25 | plugin="$1" 26 | version="${2:-latest}" 27 | ignoreLockFile="${3:-}" 28 | lock="$(getLockFile "$plugin")" 29 | 30 | if [[ $ignoreLockFile ]] || mkdir "$lock" &>/dev/null; then 31 | if ! doDownload "$plugin" "$version"; then 32 | # some plugin don't follow the rules about artifact ID 33 | # typically: docker-plugin 34 | originalPlugin="$plugin" 35 | plugin="${plugin}-plugin" 36 | if ! doDownload "$plugin" "$version"; then 37 | echo "Failed to download plugin: $originalPlugin or $plugin" >&2 38 | echo "Not downloaded: ${originalPlugin}" >> "$FAILED" 39 | return 1 40 | fi 41 | fi 42 | 43 | if ! checkIntegrity "$plugin"; then 44 | echo "Downloaded file is not a valid ZIP: $(getArchiveFilename "$plugin")" >&2 45 | echo "Download integrity: ${plugin}" >> "$FAILED" 46 | return 1 47 | fi 48 | 49 | resolveDependencies "$plugin" 50 | fi 51 | } 52 | 53 | doDownload() { 54 | local plugin version url jpi 55 | plugin="$1" 56 | version="$2" 57 | jpi="$(getArchiveFilename "$plugin")" 58 | 59 | # If plugin already exists and is the same version do not download 60 | if test -f "$jpi" && unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | grep "^Plugin-Version: ${version}$" > /dev/null; then 61 | echo "Using provided plugin: $plugin" 62 | return 0 63 | fi 64 | 65 | if [[ "$version" == "latest" && -n "$JENKINS_UC_LATEST" ]]; then 66 | # If version-specific Update Center is available, which is the case for LTS versions, 67 | # use it to resolve latest versions. 68 | url="$JENKINS_UC_LATEST/latest/${plugin}.hpi" 69 | elif [[ "$version" == "experimental" && -n "$JENKINS_UC_EXPERIMENTAL" ]]; then 70 | # Download from the experimental update center 71 | url="$JENKINS_UC_EXPERIMENTAL/latest/${plugin}.hpi" 72 | else 73 | JENKINS_UC_DOWNLOAD=${JENKINS_UC_DOWNLOAD:-"$JENKINS_UC/download"} 74 | url="$JENKINS_UC_DOWNLOAD/plugins/$plugin/$version/${plugin}.hpi" 75 | fi 76 | 77 | echo "Downloading plugin: $plugin from $url" 78 | curl --connect-timeout "${CURL_CONNECTION_TIMEOUT:-20}" --retry "${CURL_RETRY:-5}" --retry-delay "${CURL_RETRY_DELAY:-0}" --retry-max-time "${CURL_RETRY_MAX_TIME:-60}" -s -f -L "$url" -o "$jpi" 79 | return $? 80 | } 81 | 82 | checkIntegrity() { 83 | local plugin jpi 84 | plugin="$1" 85 | jpi="$(getArchiveFilename "$plugin")" 86 | 87 | unzip -t -qq "$jpi" >/dev/null 88 | return $? 89 | } 90 | 91 | resolveDependencies() { 92 | local plugin jpi dependencies 93 | plugin="$1" 94 | jpi="$(getArchiveFilename "$plugin")" 95 | 96 | dependencies="$(unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | tr '\n' '|' | sed -e 's#| ##g' | tr '|' '\n' | grep "^Plugin-Dependencies: " | sed -e 's#^Plugin-Dependencies: ##')" 97 | 98 | if [[ ! $dependencies ]]; then 99 | echo " > $plugin has no dependencies" 100 | return 101 | fi 102 | 103 | echo " > $plugin depends on $dependencies" 104 | 105 | IFS=',' read -r -a array <<< "$dependencies" 106 | 107 | for d in "${array[@]}" 108 | do 109 | plugin="$(cut -d':' -f1 - <<< "$d")" 110 | if [[ $d == *"resolution:=optional"* ]]; then 111 | echo "Skipping optional dependency $plugin" 112 | else 113 | local pluginInstalled 114 | if pluginInstalled="$(echo -e "${bundledPlugins}\n${installedPlugins}" | grep "^${plugin}:")"; then 115 | pluginInstalled="${pluginInstalled//[$'\r']}" 116 | local versionInstalled; versionInstalled=$(versionFromPlugin "${pluginInstalled}") 117 | local minVersion; minVersion=$(versionFromPlugin "${d}") 118 | if versionLT "${versionInstalled}" "${minVersion}"; then 119 | echo "Upgrading bundled dependency $d ($minVersion > $versionInstalled)" 120 | download "$plugin" & 121 | else 122 | echo "Skipping already installed dependency $d ($minVersion <= $versionInstalled)" 123 | fi 124 | else 125 | download "$plugin" & 126 | fi 127 | fi 128 | done 129 | wait 130 | } 131 | 132 | bundledPlugins() { 133 | local JENKINS_WAR=/usr/share/jenkins/jenkins.war 134 | if [ -f $JENKINS_WAR ] 135 | then 136 | TEMP_PLUGIN_DIR=/tmp/plugintemp.$$ 137 | for i in $(jar tf $JENKINS_WAR | grep -E '[^detached-]plugins.*\..pi' | sort) 138 | do 139 | rm -fr $TEMP_PLUGIN_DIR 140 | mkdir -p $TEMP_PLUGIN_DIR 141 | PLUGIN=$(basename "$i"|cut -f1 -d'.') 142 | (cd $TEMP_PLUGIN_DIR;jar xf "$JENKINS_WAR" "$i";jar xvf "$TEMP_PLUGIN_DIR/$i" META-INF/MANIFEST.MF >/dev/null 2>&1) 143 | VER=$(grep -E -i Plugin-Version "$TEMP_PLUGIN_DIR/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //') 144 | echo "$PLUGIN:$VER" 145 | done 146 | rm -fr $TEMP_PLUGIN_DIR 147 | else 148 | rm -f "$TEMP_ALREADY_INSTALLED" 149 | echo "ERROR file not found: $JENKINS_WAR" 150 | exit 1 151 | fi 152 | } 153 | 154 | versionFromPlugin() { 155 | local plugin=$1 156 | if [[ $plugin =~ .*:.* ]]; then 157 | echo "${plugin##*:}" 158 | else 159 | echo "latest" 160 | fi 161 | 162 | } 163 | 164 | installedPlugins() { 165 | for f in "$REF_DIR"/*.jpi; do 166 | echo "$(basename "$f" | sed -e 's/\.jpi//'):$(get_plugin_version "$f")" 167 | done 168 | } 169 | 170 | jenkinsMajorMinorVersion() { 171 | local JENKINS_WAR 172 | JENKINS_WAR=/usr/share/jenkins/jenkins.war 173 | if [[ -f "$JENKINS_WAR" ]]; then 174 | local version major minor 175 | version="$(java -jar /usr/share/jenkins/jenkins.war --version)" 176 | major="$(echo "$version" | cut -d '.' -f 1)" 177 | minor="$(echo "$version" | cut -d '.' -f 2)" 178 | echo "$major.$minor" 179 | else 180 | echo "ERROR file not found: $JENKINS_WAR" 181 | return 1 182 | fi 183 | } 184 | 185 | main() { 186 | local plugin pluginVersion jenkinsVersion 187 | local plugins=() 188 | 189 | mkdir -p "$REF_DIR" || exit 1 190 | 191 | # Read plugins from stdin or from the command line arguments 192 | if [[ ($# -eq 0) ]]; then 193 | while read -r line || [ "$line" != "" ]; do 194 | # Remove leading/trailing spaces, comments, and empty lines 195 | plugin=$(echo "${line}" | tr -d '\r' | sed -e 's/^[ \t]*//g' -e 's/[ \t]*$//g' -e 's/[ \t]*#.*$//g' -e '/^[ \t]*$/d') 196 | 197 | # Avoid adding empty plugin into array 198 | if [ ${#plugin} -ne 0 ]; then 199 | plugins+=("${plugin}") 200 | fi 201 | done 202 | else 203 | plugins=("$@") 204 | fi 205 | 206 | # Create lockfile manually before first run to make sure any explicit version set is used. 207 | echo "Creating initial locks..." 208 | for plugin in "${plugins[@]}"; do 209 | mkdir "$(getLockFile "${plugin%%:*}")" 210 | done 211 | 212 | echo "Analyzing war..." 213 | bundledPlugins="$(bundledPlugins)" 214 | 215 | echo "Registering preinstalled plugins..." 216 | installedPlugins="$(installedPlugins)" 217 | 218 | # Check if there's a version-specific update center, which is the case for LTS versions 219 | jenkinsVersion="$(jenkinsMajorMinorVersion)" 220 | if curl -fsL -o /dev/null "$JENKINS_UC/$jenkinsVersion"; then 221 | JENKINS_UC_LATEST="$JENKINS_UC/$jenkinsVersion" 222 | echo "Using version-specific update center: $JENKINS_UC_LATEST..." 223 | else 224 | JENKINS_UC_LATEST= 225 | fi 226 | 227 | echo "Downloading plugins..." 228 | for plugin in "${plugins[@]}"; do 229 | pluginVersion="" 230 | 231 | if [[ $plugin =~ .*:.* ]]; then 232 | pluginVersion=$(versionFromPlugin "${plugin}") 233 | plugin="${plugin%%:*}" 234 | fi 235 | 236 | download "$plugin" "$pluginVersion" "true" & 237 | done 238 | wait 239 | 240 | echo 241 | echo "WAR bundled plugins:" 242 | echo "${bundledPlugins}" 243 | echo 244 | echo "Installed plugins:" 245 | installedPlugins 246 | 247 | if [[ -f $FAILED ]]; then 248 | echo "Some plugins failed to download!" "$(<"$FAILED")" >&2 249 | exit 1 250 | fi 251 | 252 | echo "Cleaning up locks" 253 | rm -r "$REF_DIR"/*.lock 254 | } 255 | 256 | main "$@" -------------------------------------------------------------------------------- /tutorial_06/jenkins-master/jenkins-support: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | # compare if version1 < version2 4 | versionLT() { 5 | local v1; v1=$(echo "$1" | cut -d '-' -f 1 ) 6 | local q1; q1=$(echo "$1" | cut -s -d '-' -f 2- ) 7 | local v2; v2=$(echo "$2" | cut -d '-' -f 1 ) 8 | local q2; q2=$(echo "$2" | cut -s -d '-' -f 2- ) 9 | if [ "$v1" = "$v2" ]; then 10 | if [ "$q1" = "$q2" ]; then 11 | return 1 12 | else 13 | if [ -z "$q1" ]; then 14 | return 1 15 | else 16 | if [ -z "$q2" ]; then 17 | return 0 18 | else 19 | [ "$q1" = "$(echo -e "$q1\n$q2" | sort -V | head -n1)" ] 20 | fi 21 | fi 22 | fi 23 | else 24 | [ "$v1" = "$(echo -e "$v1\n$v2" | sort -V | head -n1)" ] 25 | fi 26 | } 27 | 28 | # returns a plugin version from a plugin archive 29 | get_plugin_version() { 30 | local archive; archive=$1 31 | local version; version=$(unzip -p "$archive" META-INF/MANIFEST.MF | grep "^Plugin-Version: " | sed -e 's#^Plugin-Version: ##') 32 | version=${version%%[[:space:]]} 33 | echo "$version" 34 | } 35 | 36 | # Copy files from /usr/share/jenkins/ref into $JENKINS_HOME 37 | # So the initial JENKINS-HOME is set with expected content. 38 | # Don't override, as this is just a reference setup, and use from UI 39 | # can then change this, upgrade plugins, etc. 40 | copy_reference_file() { 41 | f="${1%/}" 42 | b="${f%.override}" 43 | rel="${b:23}" 44 | version_marker="${rel}.version_from_image" 45 | dir=$(dirname "${b}") 46 | local action; 47 | local reason; 48 | local container_version; 49 | local image_version; 50 | local marker_version; 51 | local log; log=false 52 | if [[ ${rel} == plugins/*.jpi ]]; then 53 | container_version=$(get_plugin_version "$JENKINS_HOME/${rel}") 54 | image_version=$(get_plugin_version "${f}") 55 | if [[ -e $JENKINS_HOME/${version_marker} ]]; then 56 | marker_version=$(cat "$JENKINS_HOME/${version_marker}") 57 | if versionLT "$marker_version" "$container_version"; then 58 | action="SKIPPED" 59 | reason="Installed version ($container_version) has been manually upgraded from initial version ($marker_version)" 60 | log=true 61 | else 62 | if [[ "$image_version" == "$container_version" ]]; then 63 | action="SKIPPED" 64 | reason="Version from image is the same as the installed version $image_version" 65 | else 66 | if versionLT "$image_version" "$container_version"; then 67 | action="SKIPPED" 68 | log=true 69 | reason="Image version ($image_version) is older than installed version ($container_version)" 70 | else 71 | action="UPGRADED" 72 | log=true 73 | reason="Image version ($image_version) is newer than installed version ($container_version)" 74 | fi 75 | fi 76 | fi 77 | else 78 | if [[ -n "$TRY_UPGRADE_IF_NO_MARKER" ]]; then 79 | if [[ "$image_version" == "$container_version" ]]; then 80 | action="SKIPPED" 81 | reason="Version from image is the same as the installed version $image_version (no marker found)" 82 | # Add marker for next time 83 | echo "$image_version" > "$JENKINS_HOME/${version_marker}" 84 | else 85 | if versionLT "$image_version" "$container_version"; then 86 | action="SKIPPED" 87 | log=true 88 | reason="Image version ($image_version) is older than installed version ($container_version) (no marker found)" 89 | else 90 | action="UPGRADED" 91 | log=true 92 | reason="Image version ($image_version) is newer than installed version ($container_version) (no marker found)" 93 | fi 94 | fi 95 | fi 96 | fi 97 | if [[ ! -e $JENKINS_HOME/${rel} || "$action" == "UPGRADED" || $f = *.override ]]; then 98 | action=${action:-"INSTALLED"} 99 | log=true 100 | mkdir -p "$JENKINS_HOME/${dir:23}" 101 | cp -pr "${f}" "$JENKINS_HOME/${rel}"; 102 | # pin plugins on initial copy 103 | touch "$JENKINS_HOME/${rel}.pinned" 104 | echo "$image_version" > "$JENKINS_HOME/${version_marker}" 105 | reason=${reason:-$image_version} 106 | else 107 | action=${action:-"SKIPPED"} 108 | fi 109 | else 110 | if [[ ! -e $JENKINS_HOME/${rel} || $f = *.override ]] 111 | then 112 | action="INSTALLED" 113 | log=true 114 | mkdir -p "$JENKINS_HOME/${dir:23}" 115 | cp -pr "${f}" "$JENKINS_HOME/${rel}"; 116 | else 117 | action="SKIPPED" 118 | fi 119 | fi 120 | if [[ -n "$VERBOSE" || "$log" == "true" ]]; then 121 | if [ -z "$reason" ]; then 122 | echo "$action $rel" >> "$COPY_REFERENCE_FILE_LOG" 123 | else 124 | echo "$action $rel : $reason" >> "$COPY_REFERENCE_FILE_LOG" 125 | fi 126 | fi 127 | } -------------------------------------------------------------------------------- /tutorial_06/jenkins-master/jenkins.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | : "${JENKINS_WAR:="/usr/share/jenkins/jenkins.war"}" 4 | : "${JENKINS_HOME:="/var/jenkins_home"}" 5 | touch "${COPY_REFERENCE_FILE_LOG}" || { echo "Can not write to ${COPY_REFERENCE_FILE_LOG}. Wrong volume permissions?"; exit 1; } 6 | echo "--- Copying files at $(date)" >> "$COPY_REFERENCE_FILE_LOG" 7 | find /usr/share/jenkins/ref/ \( -type f -o -type l \) -exec bash -c '. /usr/local/bin/jenkins-support; for arg; do copy_reference_file "$arg"; done' _ {} + 8 | 9 | # if `docker run` first argument start with `--` the user is passing jenkins launcher arguments 10 | if [[ $# -lt 1 ]] || [[ "$1" == "--"* ]]; then 11 | 12 | # read JAVA_OPTS and JENKINS_OPTS into arrays to avoid need for eval (and associated vulnerabilities) 13 | java_opts_array=() 14 | while IFS= read -r -d '' item; do 15 | java_opts_array+=( "$item" ) 16 | done < <([[ $JAVA_OPTS ]] && xargs printf '%s\0' <<<"$JAVA_OPTS") 17 | 18 | jenkins_opts_array=( ) 19 | while IFS= read -r -d '' item; do 20 | jenkins_opts_array+=( "$item" ) 21 | done < <([[ $JENKINS_OPTS ]] && xargs printf '%s\0' <<<"$JENKINS_OPTS") 22 | 23 | exec java -Duser.home="$JENKINS_HOME" "${java_opts_array[@]}" -jar ${JENKINS_WAR} "${jenkins_opts_array[@]}" "$@" 24 | fi 25 | 26 | # As argument is not jenkins, assume user want to run his own process, for example a `bash` shell to explore this image 27 | exec "$@" -------------------------------------------------------------------------------- /tutorial_06/jenkins-master/plugins.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Parse a support-core plugin -style txt file as specification for jenkins plugins to be installed 4 | # in the reference directory, so user can define a derived Docker image with just : 5 | # 6 | # FROM jenkins 7 | # COPY plugins.txt /plugins.txt 8 | # RUN /usr/local/bin/plugins.sh /plugins.txt 9 | # 10 | # Note: Plugins already installed are skipped 11 | # 12 | 13 | set -e 14 | 15 | echo "WARN: plugins.sh is deprecated, please switch to install-plugins.sh" 16 | 17 | if [ -z "$1" ] 18 | then 19 | echo " 20 | USAGE: 21 | Parse a support-core plugin -style txt file as specification for jenkins plugins to be installed 22 | in the reference directory, so user can define a derived Docker image with just : 23 | FROM jenkins 24 | COPY plugins.txt /plugins.txt 25 | RUN /usr/local/bin/plugins.sh /plugins.txt 26 | Note: Plugins already installed are skipped 27 | " 28 | exit 1 29 | else 30 | JENKINS_INPUT_JOB_LIST=$1 31 | if [ ! -f "$JENKINS_INPUT_JOB_LIST" ] 32 | then 33 | echo "ERROR File not found: $JENKINS_INPUT_JOB_LIST" 34 | exit 1 35 | fi 36 | fi 37 | 38 | # the war includes a # of plugins, to make the build efficient filter out 39 | # the plugins so we dont install 2x - there about 17! 40 | if [ -d "$JENKINS_HOME" ] 41 | then 42 | TEMP_ALREADY_INSTALLED=$JENKINS_HOME/preinstalled.plugins.$$.txt 43 | else 44 | echo "ERROR $JENKINS_HOME not found" 45 | exit 1 46 | fi 47 | 48 | JENKINS_PLUGINS_DIR=/var/jenkins_home/plugins 49 | if [ -d "$JENKINS_PLUGINS_DIR" ] 50 | then 51 | echo "Analyzing: $JENKINS_PLUGINS_DIR" 52 | for i in "$JENKINS_PLUGINS_DIR"/*/; do 53 | JENKINS_PLUGIN=$(basename "$i") 54 | JENKINS_PLUGIN_VER=$(grep -E -i Plugin-Version "$i/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //') 55 | echo "$JENKINS_PLUGIN:$JENKINS_PLUGIN_VER" 56 | done >"$TEMP_ALREADY_INSTALLED" 57 | else 58 | JENKINS_WAR=/usr/share/jenkins/jenkins.war 59 | if [ -f "$JENKINS_WAR" ] 60 | then 61 | echo "Analyzing war: $JENKINS_WAR" 62 | TEMP_PLUGIN_DIR=/tmp/plugintemp.$$ 63 | while read -r i <&3; do 64 | rm -fr "$TEMP_PLUGIN_DIR" 65 | mkdir -p "$TEMP_PLUGIN_DIR" 66 | PLUGIN=$(basename "$i"|cut -f1 -d'.') 67 | (cd "$TEMP_PLUGIN_DIR" || exit; jar xf "$JENKINS_WAR" "$i"; jar xvf "$TEMP_PLUGIN_DIR/$i" META-INF/MANIFEST.MF >/dev/null 2>&1) 68 | VER=$(grep -E -i Plugin-Version "$TEMP_PLUGIN_DIR/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //') 69 | echo "$PLUGIN:$VER" 70 | done 3< <(jar tf "$JENKINS_WAR" | grep -E '[^detached-]plugins.*\..pi' | sort) > "$TEMP_ALREADY_INSTALLED" 71 | rm -fr "$TEMP_PLUGIN_DIR" 72 | else 73 | rm -f "$TEMP_ALREADY_INSTALLED" 74 | echo "ERROR file not found: $JENKINS_WAR" 75 | exit 1 76 | fi 77 | fi 78 | 79 | REF=/usr/share/jenkins/ref/plugins 80 | mkdir -p $REF 81 | COUNT_PLUGINS_INSTALLED=0 82 | while read -r spec || [ -n "$spec" ]; do 83 | 84 | plugin=() 85 | IFS=' ' read -r -a plugin <<< "${spec//:/ }" 86 | [[ ${plugin[0]} =~ ^# ]] && continue 87 | [[ ${plugin[0]} =~ ^[[:space:]]*$ ]] && continue 88 | [[ -z ${plugin[1]} ]] && plugin[1]="latest" 89 | 90 | if [ -z "$JENKINS_UC_DOWNLOAD" ]; then 91 | JENKINS_UC_DOWNLOAD=$JENKINS_UC/download 92 | fi 93 | 94 | if ! grep -q "${plugin[0]}:${plugin[1]}" "$TEMP_ALREADY_INSTALLED" 95 | then 96 | echo "Downloading ${plugin[0]}:${plugin[1]}" 97 | curl --retry 3 --retry-delay 5 -sSL -f "${JENKINS_UC_DOWNLOAD}/plugins/${plugin[0]}/${plugin[1]}/${plugin[0]}.hpi" -o "$REF/${plugin[0]}.jpi" 98 | unzip -qqt "$REF/${plugin[0]}.jpi" 99 | (( COUNT_PLUGINS_INSTALLED += 1 )) 100 | else 101 | echo " ... skipping already installed: ${plugin[0]}:${plugin[1]}" 102 | fi 103 | done < "$JENKINS_INPUT_JOB_LIST" 104 | 105 | echo "---------------------------------------------------" 106 | if (( "$COUNT_PLUGINS_INSTALLED" > 0 )) 107 | then 108 | echo "INFO: Successfully installed $COUNT_PLUGINS_INSTALLED plugins." 109 | 110 | if [ -d $JENKINS_PLUGINS_DIR ] 111 | then 112 | echo "INFO: Please restart the container for changes to take effect!" 113 | fi 114 | else 115 | echo "INFO: No changes, all plugins previously installed." 116 | 117 | fi 118 | echo "---------------------------------------------------" 119 | 120 | #cleanup 121 | rm "$TEMP_ALREADY_INSTALLED" 122 | exit 0 -------------------------------------------------------------------------------- /tutorial_06/jenkins-nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Install NGINX 5 | RUN yum -y update; yum clean all 6 | RUN yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm; yum -y makecache 7 | RUN yum -y install nginx-1.10.1 8 | 9 | # Remove default files we don't need 10 | RUN rm /etc/nginx/conf.d/default.conf 11 | 12 | # Add default configuration 13 | COPY conf/jenkins.conf /etc/nginx/conf.d/jenkins.conf 14 | COPY conf/nginx.conf /etc/nginx/nginx.conf 15 | 16 | EXPOSE 80 17 | 18 | CMD ["nginx"] -------------------------------------------------------------------------------- /tutorial_06/jenkins-nginx/conf/jenkins.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name ""; 4 | 5 | access_log off; 6 | 7 | location / { 8 | proxy_pass http://jenkins_master_1:8080; 9 | 10 | proxy_set_header Host $host; 11 | proxy_set_header X-Real-IP $remote_addr; 12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 13 | proxy_set_header X-Forwarded-Proto http; 14 | proxy_max_temp_file_size 0; 15 | 16 | proxy_connect_timeout 150; 17 | proxy_send_timeout 100; 18 | proxy_read_timeout 100; 19 | 20 | proxy_buffer_size 8k; 21 | proxy_buffers 4 32k; 22 | proxy_busy_buffers_size 64k; 23 | proxy_temp_file_write_size 64k; 24 | 25 | 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /tutorial_06/jenkins-nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | user nginx; 3 | worker_processes 2; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | use epoll; 12 | accept_mutex off; 13 | } 14 | 15 | 16 | http { 17 | include /etc/nginx/mime.types; 18 | proxy_set_header X-Real-IP $remote_addr; 19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | 21 | default_type application/octet-stream; 22 | 23 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 24 | '$status $body_bytes_sent "$http_referer" ' 25 | '"$http_user_agent" "$http_x_forwarded_for"'; 26 | 27 | access_log /var/log/nginx/access.log main; 28 | 29 | sendfile on; 30 | #tcp_nopush on; 31 | 32 | keepalive_timeout 65; 33 | 34 | client_max_body_size 300m; 35 | client_body_buffer_size 128k; 36 | 37 | gzip on; 38 | gzip_http_version 1.0; 39 | gzip_comp_level 6; 40 | gzip_min_length 0; 41 | gzip_buffers 16 8k; 42 | gzip_proxied any; 43 | gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json; 44 | gzip_disable "MSIE [1-6]\."; 45 | gzip_vary on; 46 | 47 | include /etc/nginx/conf.d/*.conf; 48 | } 49 | -------------------------------------------------------------------------------- /tutorial_06/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker-compose -p jenkins build 3 | run: 4 | @docker-compose -p jenkins up -d 5 | stop: 6 | @docker-compose -p jenkins down 7 | clean-data: 8 | @docker-compose -p jenkins down -v 9 | clean-images: 10 | @docker rmi $(shell docker images -q -f "dangling=true") 11 | jenkins-log: 12 | @docker-compose -p jenkins exec master tail -f /var/log/jenkins/jenkins.log 13 | 14 | 15 | -------------------------------------------------------------------------------- /tutorial_07/README.md: -------------------------------------------------------------------------------- 1 | The tutorial for this makefile can be found here: http://engineering.riotgames.com/news/building-jenkins-inside-ephemeral-docker-container 2 | 3 | # Ephemeral Build Slaves using Jenkins and Docker 4 | 5 | This tutorial contains all the files necessary to create your own local Docker-Toolbox version of a fully ephemeral jenkins environment. Build slaves are designed to 6 | be docker containers in this configuration. The only thing missing to make it work is your Docker Machine certs (see directions below on how to add these). 7 | 8 | # Quick Start 9 | 10 | Ideally you'll follow along with the entire blog series. However if you'd like to get this up and running as quickly as possible here's the steps you need to do: 11 | 12 | 1. Make sure you have all the pre-reqs installed (i.e. Docker-toolbox) 13 | 2. Clone this repository to your local drive 14 | 3. Find the docker-machine folder container your 4 client pem keys (ca-key.pem, ca.pem, key.pem, cert.pem). Mine for example, is in ~/.docker/machine/certs. 15 | 4. cp -R yourdockermachinecertsfolder jenkins-master/certs 16 | 5. make build 17 | 6. make run 18 | 7. Point your browser to http://yourdockermachineip 19 | 8. In jenkins, configure a ssh-key pair using an ssh private key for the user "jenkins". As the private key, use the file in jenkins-slave/files/dummy\_private\_rsa\_key 20 | 9. In jenkins, configure a Docker Certificates Directory credential using /usr/local/etc/jenkins/certs as the source directory 21 | 10. In jenkins configuration, add a new Docker cloud provider 22 | 1. Set host to https://yourdockermachineip:2376 23 | 2. Select the docker certificates directory you made 24 | 3. Set read timeout to 5 25 | 4. set connection timeout to 15 26 | 5. Click on "Test COnnection" and make sure you get a valid response 27 | 11. In jenkins config on your new Docker cloud add a Docker template 28 | 1. Set the image name to: jenkins\_slave 29 | 2. Create a label "testslave" 30 | 3. Make sure credentials are your new ssh key pair you made above 31 | 4. Click "Save" 32 | 12. Create a new free-style jenkins job 33 | 1. Restrict the job to the label "testslave" 34 | 2. Add a build step, like execute shell "echo 'Hello World!'" 35 | 3. Save job 36 | 4. Run job 37 | 38 | If everything is configured correctly your job should dynamically allocate a slave, run itself and then de-allocate the slave. 39 | -------------------------------------------------------------------------------- /tutorial_07/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | master: 4 | build: ./jenkins-master 5 | ports: 6 | - "50000:50000" 7 | volumes: 8 | - jenkins-log:/var/log/jenkins 9 | - jenkins-data:/var/jenkins_home 10 | networks: 11 | - jenkins-net 12 | nginx: 13 | build: ./jenkins-nginx 14 | ports: 15 | - "80:80" 16 | networks: 17 | - jenkins-net 18 | slave: 19 | build: ./jenkins-slave 20 | proxy: 21 | build: ./docker-proxy 22 | volumes: 23 | - /var/run/docker.sock:/var/run/docker.sock 24 | networks: 25 | jenkins-net: 26 | aliases: 27 | - proxy1 28 | volumes: 29 | jenkins-data: 30 | jenkins-log: 31 | networks: 32 | jenkins-net: 33 | 34 | 35 | -------------------------------------------------------------------------------- /tutorial_07/docker-proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | RUN yum -y install socat && \ 5 | yum clean all 6 | 7 | VOLUME /var/run/docker.sock 8 | 9 | # docker tcp port 10 | EXPOSE 2375 11 | 12 | ENTRYPOINT ["socat", "TCP-LISTEN:2375,reuseaddr,fork","UNIX-CLIENT:/var/run/docker.sock"] -------------------------------------------------------------------------------- /tutorial_07/jenkins-master/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | RUN yum makecache \ 5 | && yum update -y \ 6 | && yum install -y \ 7 | wget \ 8 | zip \ 9 | openssh-client \ 10 | unzip \ 11 | java-1.8.0-openjdk \ 12 | && yum clean all 13 | 14 | ARG user=jenkins 15 | ARG group=jenkins 16 | ARG uid=1000 17 | ARG gid=1000 18 | ARG http_port=8080 19 | ARG agent_port=50000 20 | ARG JENKINS_VERSION=2.112 21 | ARG TINI_VERSION=v0.17.0 22 | 23 | # jenkins.war checksum, download will be validated using it 24 | ARG JENKINS_SHA=085f597edeb0d49d54d7653f3742ba31ed72b8a1a2b053d2eb23fd806c6a5393 25 | 26 | # Can be used to customize where jenkins.war get downloaded from 27 | ARG JENKINS_URL=https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/${JENKINS_VERSION}/jenkins-war-${JENKINS_VERSION}.war 28 | 29 | ENV JENKINS_VERSION ${JENKINS_VERSION} 30 | ENV JENKINS_HOME /var/jenkins_home 31 | ENV JENKINS_SLAVE_AGENT_PORT ${agent_port} 32 | ENV JENKINS_UC https://updates.jenkins.io 33 | ENV JENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimental 34 | ENV JAVA_OPTS="-Xmx8192m -Djenkins.install.runSetupWizard=false" 35 | ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" 36 | ENV COPY_REFERENCE_FILE_LOG $JENKINS_HOME/copy_reference_file.log 37 | 38 | # Use tini as subreaper in Docker container to adopt zombie processes 39 | ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /bin/tini 40 | RUN chmod +x /bin/tini 41 | 42 | # Jenkins is run with user `jenkins`, uid = 1000 43 | # If you bind mount a volume from the host or a data container, 44 | # ensure you use the same uid 45 | RUN groupadd -g ${gid} ${group} \ 46 | && useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user} 47 | 48 | # Jenkins home directory is a volume, so configuration and build history 49 | # can be persisted and survive image upgrades 50 | VOLUME /var/jenkins_home 51 | 52 | # `/usr/share/jenkins/ref/` contains all reference configuration we want 53 | # to set on a fresh new installation. Use it to bundle additional plugins 54 | # or config file with your custom jenkins Docker image. 55 | RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d 56 | 57 | # Install Jenkins 58 | # could use ADD but this one does not check Last-Modified header neither does it allow to control checksum 59 | # see https://github.com/docker/docker/issues/8331 60 | RUN curl -fsSL ${JENKINS_URL} -o /usr/share/jenkins/jenkins.war \ 61 | && echo "${JENKINS_SHA} /usr/share/jenkins/jenkins.war" | sha256sum -c - 62 | 63 | # Prep Jenkins Directories 64 | RUN chown -R ${user} "$JENKINS_HOME" /usr/share/jenkins/ref 65 | RUN mkdir /var/log/jenkins 66 | RUN mkdir /var/cache/jenkins 67 | RUN chown -R ${user}:${user} /var/log/jenkins 68 | RUN chown -R ${user}:${user} /var/cache/jenkins 69 | 70 | # Expose Ports for web and slave agents 71 | EXPOSE ${http_port} 72 | EXPOSE ${agent_port} 73 | 74 | # Copy in local config files 75 | COPY init.groovy /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy 76 | COPY jenkins-support /usr/local/bin/jenkins-support 77 | COPY plugins.sh /usr/local/bin/plugins.sh 78 | COPY jenkins.sh /usr/local/bin/jenkins.sh 79 | COPY install-plugins.sh /usr/local/bin/install-plugins.sh 80 | RUN chmod +x /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy \ 81 | && chmod +x /usr/local/bin/jenkins-support \ 82 | && chmod +x /usr/local/bin/plugins.sh \ 83 | && chmod +x /usr/local/bin/jenkins.sh \ 84 | && chmod +x /usr/local/bin/install-plugins.sh 85 | 86 | # Install default plugins 87 | COPY plugins.txt /tmp/plugins.txt 88 | RUN /usr/local/bin/install-plugins.sh < /tmp/plugins.txt 89 | 90 | # Switch to the jenkins user 91 | USER ${user} 92 | 93 | # Tini as the entry point to manage zombie processes 94 | ENTRYPOINT ["/bin/tini", "--", "/usr/local/bin/jenkins.sh"] 95 | 96 | -------------------------------------------------------------------------------- /tutorial_07/jenkins-master/Dockerfile-debian: -------------------------------------------------------------------------------- 1 | FROM debian:stretch 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | ENV LANG C.UTF-8 5 | ENV JAVA_VERSION 8u162 6 | ENV JAVA_DEBIAN_VERSION 8u162-b12-1~deb9u1 7 | 8 | # see https://bugs.debian.org/775775 9 | # and https://github.com/docker-library/java/issues/19#issuecomment-70546872 10 | ENV CA_CERTIFICATES_JAVA_VERSION 20170531+nmu1 11 | 12 | RUN apt-get update \ 13 | && apt-get install -y --no-install-recommends \ 14 | wget \ 15 | curl \ 16 | ca-certificates \ 17 | zip \ 18 | openssh-client \ 19 | unzip \ 20 | openjdk-8-jdk="$JAVA_DEBIAN_VERSION" \ 21 | ca-certificates-java="$CA_CERTIFICATES_JAVA_VERSION" \ 22 | && rm -rf /var/lib/apt/lists/* 23 | 24 | RUN /var/lib/dpkg/info/ca-certificates-java.postinst configure 25 | 26 | ARG user=jenkins 27 | ARG group=jenkins 28 | ARG uid=1000 29 | ARG gid=1000 30 | ARG http_port=8080 31 | ARG agent_port=50000 32 | ARG JENKINS_VERSION=2.112 33 | ARG TINI_VERSION=v0.17.0 34 | 35 | # jenkins.war checksum, download will be validated using it 36 | ARG JENKINS_SHA=085f597edeb0d49d54d7653f3742ba31ed72b8a1a2b053d2eb23fd806c6a5393 37 | 38 | # Can be used to customize where jenkins.war get downloaded from 39 | ARG JENKINS_URL=https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/${JENKINS_VERSION}/jenkins-war-${JENKINS_VERSION}.war 40 | 41 | ENV JENKINS_VERSION ${JENKINS_VERSION} 42 | ENV JENKINS_HOME /var/jenkins_home 43 | ENV JENKINS_SLAVE_AGENT_PORT ${agent_port} 44 | ENV JENKINS_UC https://updates.jenkins.io 45 | ENV JENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimental 46 | ENV JAVA_OPTS="-Xmx8192m -Djenkins.install.runSetupWizard=false" 47 | ENV JENKINS_OPTS="--handlerCountMax=300 --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" 48 | ENV COPY_REFERENCE_FILE_LOG $JENKINS_HOME/copy_reference_file.log 49 | 50 | # Use tini as subreaper in Docker container to adopt zombie processes 51 | RUN curl -fsSL https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static-$(dpkg --print-architecture) -o /sbin/tini \ 52 | && chmod +x /sbin/tini 53 | 54 | # Jenkins is run with user `jenkins`, uid = 1000 55 | # If you bind mount a volume from the host or a data container, 56 | # ensure you use the same uid 57 | RUN groupadd -g ${gid} ${group} \ 58 | && useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user} 59 | 60 | # Jenkins home directory is a volume, so configuration and build history 61 | # can be persisted and survive image upgrades 62 | VOLUME /var/jenkins_home 63 | 64 | # `/usr/share/jenkins/ref/` contains all reference configuration we want 65 | # to set on a fresh new installation. Use it to bundle additional plugins 66 | # or config file with your custom jenkins Docker image. 67 | RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d 68 | 69 | # could use ADD but this one does not check Last-Modified header neither does it allow to control checksum 70 | # see https://github.com/docker/docker/issues/8331 71 | RUN curl -fsSL ${JENKINS_URL} -o /usr/share/jenkins/jenkins.war \ 72 | && echo "${JENKINS_SHA} /usr/share/jenkins/jenkins.war" | sha256sum -c - 73 | 74 | RUN chown -R ${user} "$JENKINS_HOME" /usr/share/jenkins/ref 75 | RUN mkdir /var/log/jenkins 76 | RUN mkdir /var/cache/jenkins 77 | RUN chown -R ${user}:${user} /var/log/jenkins 78 | RUN chown -R ${user}:${user} /var/cache/jenkins 79 | 80 | # for main web and slave agents: 81 | EXPOSE ${http_port} 82 | EXPOSE ${agent_port} 83 | 84 | # Copy in local config files 85 | COPY init.groovy /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy 86 | COPY jenkins-support /usr/local/bin/jenkins-support 87 | COPY plugins.sh /usr/local/bin/plugins.sh 88 | COPY jenkins.sh /usr/local/bin/jenkins.sh 89 | COPY install-plugins.sh /usr/local/bin/install-plugins.sh 90 | RUN chmod +x /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy \ 91 | && chmod +x /usr/local/bin/jenkins-support \ 92 | && chmod +x /usr/local/bin/plugins.sh \ 93 | && chmod +x /usr/local/bin/jenkins.sh \ 94 | && chmod +x /usr/local/bin/install-plugins.sh 95 | 96 | # Install default plugins 97 | COPY plugins.txt /tmp/plugins.txt 98 | RUN /usr/local/bin/install-plugins.sh < /tmp/plugins.txt 99 | 100 | USER ${user} 101 | 102 | ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/jenkins.sh"] 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /tutorial_07/jenkins-master/init.groovy: -------------------------------------------------------------------------------- 1 | import hudson.model.*; 2 | import jenkins.model.*; 3 | 4 | 5 | Thread.start { 6 | sleep 10000 7 | println "--> setting agent port for jnlp" 8 | def env = System.getenv() 9 | int port = env['JENKINS_SLAVE_AGENT_PORT'].toInteger() 10 | Jenkins.instance.setSlaveAgentPort(port) 11 | println "--> setting agent port for jnlp... done" 12 | } 13 | -------------------------------------------------------------------------------- /tutorial_07/jenkins-master/install-plugins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | # Resolve dependencies and download plugins given on the command line 4 | # 5 | # FROM jenkins 6 | # RUN install-plugins.sh docker-slaves github-branch-source 7 | 8 | set -o pipefail 9 | 10 | REF_DIR=${REF:-/usr/share/jenkins/ref/plugins} 11 | FAILED="$REF_DIR/failed-plugins.txt" 12 | 13 | . /usr/local/bin/jenkins-support 14 | 15 | getLockFile() { 16 | printf '%s' "$REF_DIR/${1}.lock" 17 | } 18 | 19 | getArchiveFilename() { 20 | printf '%s' "$REF_DIR/${1}.jpi" 21 | } 22 | 23 | download() { 24 | local plugin originalPlugin version lock ignoreLockFile 25 | plugin="$1" 26 | version="${2:-latest}" 27 | ignoreLockFile="${3:-}" 28 | lock="$(getLockFile "$plugin")" 29 | 30 | if [[ $ignoreLockFile ]] || mkdir "$lock" &>/dev/null; then 31 | if ! doDownload "$plugin" "$version"; then 32 | # some plugin don't follow the rules about artifact ID 33 | # typically: docker-plugin 34 | originalPlugin="$plugin" 35 | plugin="${plugin}-plugin" 36 | if ! doDownload "$plugin" "$version"; then 37 | echo "Failed to download plugin: $originalPlugin or $plugin" >&2 38 | echo "Not downloaded: ${originalPlugin}" >> "$FAILED" 39 | return 1 40 | fi 41 | fi 42 | 43 | if ! checkIntegrity "$plugin"; then 44 | echo "Downloaded file is not a valid ZIP: $(getArchiveFilename "$plugin")" >&2 45 | echo "Download integrity: ${plugin}" >> "$FAILED" 46 | return 1 47 | fi 48 | 49 | resolveDependencies "$plugin" 50 | fi 51 | } 52 | 53 | doDownload() { 54 | local plugin version url jpi 55 | plugin="$1" 56 | version="$2" 57 | jpi="$(getArchiveFilename "$plugin")" 58 | 59 | # If plugin already exists and is the same version do not download 60 | if test -f "$jpi" && unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | grep "^Plugin-Version: ${version}$" > /dev/null; then 61 | echo "Using provided plugin: $plugin" 62 | return 0 63 | fi 64 | 65 | if [[ "$version" == "latest" && -n "$JENKINS_UC_LATEST" ]]; then 66 | # If version-specific Update Center is available, which is the case for LTS versions, 67 | # use it to resolve latest versions. 68 | url="$JENKINS_UC_LATEST/latest/${plugin}.hpi" 69 | elif [[ "$version" == "experimental" && -n "$JENKINS_UC_EXPERIMENTAL" ]]; then 70 | # Download from the experimental update center 71 | url="$JENKINS_UC_EXPERIMENTAL/latest/${plugin}.hpi" 72 | else 73 | JENKINS_UC_DOWNLOAD=${JENKINS_UC_DOWNLOAD:-"$JENKINS_UC/download"} 74 | url="$JENKINS_UC_DOWNLOAD/plugins/$plugin/$version/${plugin}.hpi" 75 | fi 76 | 77 | echo "Downloading plugin: $plugin from $url" 78 | curl --connect-timeout "${CURL_CONNECTION_TIMEOUT:-20}" --retry "${CURL_RETRY:-5}" --retry-delay "${CURL_RETRY_DELAY:-0}" --retry-max-time "${CURL_RETRY_MAX_TIME:-60}" -s -f -L "$url" -o "$jpi" 79 | return $? 80 | } 81 | 82 | checkIntegrity() { 83 | local plugin jpi 84 | plugin="$1" 85 | jpi="$(getArchiveFilename "$plugin")" 86 | 87 | unzip -t -qq "$jpi" >/dev/null 88 | return $? 89 | } 90 | 91 | resolveDependencies() { 92 | local plugin jpi dependencies 93 | plugin="$1" 94 | jpi="$(getArchiveFilename "$plugin")" 95 | 96 | dependencies="$(unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | tr '\n' '|' | sed -e 's#| ##g' | tr '|' '\n' | grep "^Plugin-Dependencies: " | sed -e 's#^Plugin-Dependencies: ##')" 97 | 98 | if [[ ! $dependencies ]]; then 99 | echo " > $plugin has no dependencies" 100 | return 101 | fi 102 | 103 | echo " > $plugin depends on $dependencies" 104 | 105 | IFS=',' read -r -a array <<< "$dependencies" 106 | 107 | for d in "${array[@]}" 108 | do 109 | plugin="$(cut -d':' -f1 - <<< "$d")" 110 | if [[ $d == *"resolution:=optional"* ]]; then 111 | echo "Skipping optional dependency $plugin" 112 | else 113 | local pluginInstalled 114 | if pluginInstalled="$(echo -e "${bundledPlugins}\n${installedPlugins}" | grep "^${plugin}:")"; then 115 | pluginInstalled="${pluginInstalled//[$'\r']}" 116 | local versionInstalled; versionInstalled=$(versionFromPlugin "${pluginInstalled}") 117 | local minVersion; minVersion=$(versionFromPlugin "${d}") 118 | if versionLT "${versionInstalled}" "${minVersion}"; then 119 | echo "Upgrading bundled dependency $d ($minVersion > $versionInstalled)" 120 | download "$plugin" & 121 | else 122 | echo "Skipping already installed dependency $d ($minVersion <= $versionInstalled)" 123 | fi 124 | else 125 | download "$plugin" & 126 | fi 127 | fi 128 | done 129 | wait 130 | } 131 | 132 | bundledPlugins() { 133 | local JENKINS_WAR=/usr/share/jenkins/jenkins.war 134 | if [ -f $JENKINS_WAR ] 135 | then 136 | TEMP_PLUGIN_DIR=/tmp/plugintemp.$$ 137 | for i in $(jar tf $JENKINS_WAR | grep -E '[^detached-]plugins.*\..pi' | sort) 138 | do 139 | rm -fr $TEMP_PLUGIN_DIR 140 | mkdir -p $TEMP_PLUGIN_DIR 141 | PLUGIN=$(basename "$i"|cut -f1 -d'.') 142 | (cd $TEMP_PLUGIN_DIR;jar xf "$JENKINS_WAR" "$i";jar xvf "$TEMP_PLUGIN_DIR/$i" META-INF/MANIFEST.MF >/dev/null 2>&1) 143 | VER=$(grep -E -i Plugin-Version "$TEMP_PLUGIN_DIR/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //') 144 | echo "$PLUGIN:$VER" 145 | done 146 | rm -fr $TEMP_PLUGIN_DIR 147 | else 148 | rm -f "$TEMP_ALREADY_INSTALLED" 149 | echo "ERROR file not found: $JENKINS_WAR" 150 | exit 1 151 | fi 152 | } 153 | 154 | versionFromPlugin() { 155 | local plugin=$1 156 | if [[ $plugin =~ .*:.* ]]; then 157 | echo "${plugin##*:}" 158 | else 159 | echo "latest" 160 | fi 161 | 162 | } 163 | 164 | installedPlugins() { 165 | for f in "$REF_DIR"/*.jpi; do 166 | echo "$(basename "$f" | sed -e 's/\.jpi//'):$(get_plugin_version "$f")" 167 | done 168 | } 169 | 170 | jenkinsMajorMinorVersion() { 171 | local JENKINS_WAR 172 | JENKINS_WAR=/usr/share/jenkins/jenkins.war 173 | if [[ -f "$JENKINS_WAR" ]]; then 174 | local version major minor 175 | version="$(java -jar /usr/share/jenkins/jenkins.war --version)" 176 | major="$(echo "$version" | cut -d '.' -f 1)" 177 | minor="$(echo "$version" | cut -d '.' -f 2)" 178 | echo "$major.$minor" 179 | else 180 | echo "ERROR file not found: $JENKINS_WAR" 181 | return 1 182 | fi 183 | } 184 | 185 | main() { 186 | local plugin pluginVersion jenkinsVersion 187 | local plugins=() 188 | 189 | mkdir -p "$REF_DIR" || exit 1 190 | 191 | # Read plugins from stdin or from the command line arguments 192 | if [[ ($# -eq 0) ]]; then 193 | while read -r line || [ "$line" != "" ]; do 194 | # Remove leading/trailing spaces, comments, and empty lines 195 | plugin=$(echo "${line}" | tr -d '\r' | sed -e 's/^[ \t]*//g' -e 's/[ \t]*$//g' -e 's/[ \t]*#.*$//g' -e '/^[ \t]*$/d') 196 | 197 | # Avoid adding empty plugin into array 198 | if [ ${#plugin} -ne 0 ]; then 199 | plugins+=("${plugin}") 200 | fi 201 | done 202 | else 203 | plugins=("$@") 204 | fi 205 | 206 | # Create lockfile manually before first run to make sure any explicit version set is used. 207 | echo "Creating initial locks..." 208 | for plugin in "${plugins[@]}"; do 209 | mkdir "$(getLockFile "${plugin%%:*}")" 210 | done 211 | 212 | echo "Analyzing war..." 213 | bundledPlugins="$(bundledPlugins)" 214 | 215 | echo "Registering preinstalled plugins..." 216 | installedPlugins="$(installedPlugins)" 217 | 218 | # Check if there's a version-specific update center, which is the case for LTS versions 219 | jenkinsVersion="$(jenkinsMajorMinorVersion)" 220 | if curl -fsL -o /dev/null "$JENKINS_UC/$jenkinsVersion"; then 221 | JENKINS_UC_LATEST="$JENKINS_UC/$jenkinsVersion" 222 | echo "Using version-specific update center: $JENKINS_UC_LATEST..." 223 | else 224 | JENKINS_UC_LATEST= 225 | fi 226 | 227 | echo "Downloading plugins..." 228 | for plugin in "${plugins[@]}"; do 229 | pluginVersion="" 230 | 231 | if [[ $plugin =~ .*:.* ]]; then 232 | pluginVersion=$(versionFromPlugin "${plugin}") 233 | plugin="${plugin%%:*}" 234 | fi 235 | 236 | download "$plugin" "$pluginVersion" "true" & 237 | done 238 | wait 239 | 240 | echo 241 | echo "WAR bundled plugins:" 242 | echo "${bundledPlugins}" 243 | echo 244 | echo "Installed plugins:" 245 | installedPlugins 246 | 247 | if [[ -f $FAILED ]]; then 248 | echo "Some plugins failed to download!" "$(<"$FAILED")" >&2 249 | exit 1 250 | fi 251 | 252 | echo "Cleaning up locks" 253 | rm -r "$REF_DIR"/*.lock 254 | } 255 | 256 | main "$@" -------------------------------------------------------------------------------- /tutorial_07/jenkins-master/jenkins-support: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | # compare if version1 < version2 4 | versionLT() { 5 | local v1; v1=$(echo "$1" | cut -d '-' -f 1 ) 6 | local q1; q1=$(echo "$1" | cut -s -d '-' -f 2- ) 7 | local v2; v2=$(echo "$2" | cut -d '-' -f 1 ) 8 | local q2; q2=$(echo "$2" | cut -s -d '-' -f 2- ) 9 | if [ "$v1" = "$v2" ]; then 10 | if [ "$q1" = "$q2" ]; then 11 | return 1 12 | else 13 | if [ -z "$q1" ]; then 14 | return 1 15 | else 16 | if [ -z "$q2" ]; then 17 | return 0 18 | else 19 | [ "$q1" = "$(echo -e "$q1\n$q2" | sort -V | head -n1)" ] 20 | fi 21 | fi 22 | fi 23 | else 24 | [ "$v1" = "$(echo -e "$v1\n$v2" | sort -V | head -n1)" ] 25 | fi 26 | } 27 | 28 | # returns a plugin version from a plugin archive 29 | get_plugin_version() { 30 | local archive; archive=$1 31 | local version; version=$(unzip -p "$archive" META-INF/MANIFEST.MF | grep "^Plugin-Version: " | sed -e 's#^Plugin-Version: ##') 32 | version=${version%%[[:space:]]} 33 | echo "$version" 34 | } 35 | 36 | # Copy files from /usr/share/jenkins/ref into $JENKINS_HOME 37 | # So the initial JENKINS-HOME is set with expected content. 38 | # Don't override, as this is just a reference setup, and use from UI 39 | # can then change this, upgrade plugins, etc. 40 | copy_reference_file() { 41 | f="${1%/}" 42 | b="${f%.override}" 43 | rel="${b:23}" 44 | version_marker="${rel}.version_from_image" 45 | dir=$(dirname "${b}") 46 | local action; 47 | local reason; 48 | local container_version; 49 | local image_version; 50 | local marker_version; 51 | local log; log=false 52 | if [[ ${rel} == plugins/*.jpi ]]; then 53 | container_version=$(get_plugin_version "$JENKINS_HOME/${rel}") 54 | image_version=$(get_plugin_version "${f}") 55 | if [[ -e $JENKINS_HOME/${version_marker} ]]; then 56 | marker_version=$(cat "$JENKINS_HOME/${version_marker}") 57 | if versionLT "$marker_version" "$container_version"; then 58 | action="SKIPPED" 59 | reason="Installed version ($container_version) has been manually upgraded from initial version ($marker_version)" 60 | log=true 61 | else 62 | if [[ "$image_version" == "$container_version" ]]; then 63 | action="SKIPPED" 64 | reason="Version from image is the same as the installed version $image_version" 65 | else 66 | if versionLT "$image_version" "$container_version"; then 67 | action="SKIPPED" 68 | log=true 69 | reason="Image version ($image_version) is older than installed version ($container_version)" 70 | else 71 | action="UPGRADED" 72 | log=true 73 | reason="Image version ($image_version) is newer than installed version ($container_version)" 74 | fi 75 | fi 76 | fi 77 | else 78 | if [[ -n "$TRY_UPGRADE_IF_NO_MARKER" ]]; then 79 | if [[ "$image_version" == "$container_version" ]]; then 80 | action="SKIPPED" 81 | reason="Version from image is the same as the installed version $image_version (no marker found)" 82 | # Add marker for next time 83 | echo "$image_version" > "$JENKINS_HOME/${version_marker}" 84 | else 85 | if versionLT "$image_version" "$container_version"; then 86 | action="SKIPPED" 87 | log=true 88 | reason="Image version ($image_version) is older than installed version ($container_version) (no marker found)" 89 | else 90 | action="UPGRADED" 91 | log=true 92 | reason="Image version ($image_version) is newer than installed version ($container_version) (no marker found)" 93 | fi 94 | fi 95 | fi 96 | fi 97 | if [[ ! -e $JENKINS_HOME/${rel} || "$action" == "UPGRADED" || $f = *.override ]]; then 98 | action=${action:-"INSTALLED"} 99 | log=true 100 | mkdir -p "$JENKINS_HOME/${dir:23}" 101 | cp -pr "${f}" "$JENKINS_HOME/${rel}"; 102 | # pin plugins on initial copy 103 | touch "$JENKINS_HOME/${rel}.pinned" 104 | echo "$image_version" > "$JENKINS_HOME/${version_marker}" 105 | reason=${reason:-$image_version} 106 | else 107 | action=${action:-"SKIPPED"} 108 | fi 109 | else 110 | if [[ ! -e $JENKINS_HOME/${rel} || $f = *.override ]] 111 | then 112 | action="INSTALLED" 113 | log=true 114 | mkdir -p "$JENKINS_HOME/${dir:23}" 115 | cp -pr "${f}" "$JENKINS_HOME/${rel}"; 116 | else 117 | action="SKIPPED" 118 | fi 119 | fi 120 | if [[ -n "$VERBOSE" || "$log" == "true" ]]; then 121 | if [ -z "$reason" ]; then 122 | echo "$action $rel" >> "$COPY_REFERENCE_FILE_LOG" 123 | else 124 | echo "$action $rel : $reason" >> "$COPY_REFERENCE_FILE_LOG" 125 | fi 126 | fi 127 | } -------------------------------------------------------------------------------- /tutorial_07/jenkins-master/jenkins.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | : "${JENKINS_WAR:="/usr/share/jenkins/jenkins.war"}" 4 | : "${JENKINS_HOME:="/var/jenkins_home"}" 5 | touch "${COPY_REFERENCE_FILE_LOG}" || { echo "Can not write to ${COPY_REFERENCE_FILE_LOG}. Wrong volume permissions?"; exit 1; } 6 | echo "--- Copying files at $(date)" >> "$COPY_REFERENCE_FILE_LOG" 7 | find /usr/share/jenkins/ref/ \( -type f -o -type l \) -exec bash -c '. /usr/local/bin/jenkins-support; for arg; do copy_reference_file "$arg"; done' _ {} + 8 | 9 | # if `docker run` first argument start with `--` the user is passing jenkins launcher arguments 10 | if [[ $# -lt 1 ]] || [[ "$1" == "--"* ]]; then 11 | 12 | # read JAVA_OPTS and JENKINS_OPTS into arrays to avoid need for eval (and associated vulnerabilities) 13 | java_opts_array=() 14 | while IFS= read -r -d '' item; do 15 | java_opts_array+=( "$item" ) 16 | done < <([[ $JAVA_OPTS ]] && xargs printf '%s\0' <<<"$JAVA_OPTS") 17 | 18 | jenkins_opts_array=( ) 19 | while IFS= read -r -d '' item; do 20 | jenkins_opts_array+=( "$item" ) 21 | done < <([[ $JENKINS_OPTS ]] && xargs printf '%s\0' <<<"$JENKINS_OPTS") 22 | 23 | exec java -Duser.home="$JENKINS_HOME" "${java_opts_array[@]}" -jar ${JENKINS_WAR} "${jenkins_opts_array[@]}" "$@" 24 | fi 25 | 26 | # As argument is not jenkins, assume user want to run his own process, for example a `bash` shell to explore this image 27 | exec "$@" -------------------------------------------------------------------------------- /tutorial_07/jenkins-master/plugins.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Parse a support-core plugin -style txt file as specification for jenkins plugins to be installed 4 | # in the reference directory, so user can define a derived Docker image with just : 5 | # 6 | # FROM jenkins 7 | # COPY plugins.txt /plugins.txt 8 | # RUN /usr/local/bin/plugins.sh /plugins.txt 9 | # 10 | # Note: Plugins already installed are skipped 11 | # 12 | 13 | set -e 14 | 15 | echo "WARN: plugins.sh is deprecated, please switch to install-plugins.sh" 16 | 17 | if [ -z "$1" ] 18 | then 19 | echo " 20 | USAGE: 21 | Parse a support-core plugin -style txt file as specification for jenkins plugins to be installed 22 | in the reference directory, so user can define a derived Docker image with just : 23 | FROM jenkins 24 | COPY plugins.txt /plugins.txt 25 | RUN /usr/local/bin/plugins.sh /plugins.txt 26 | Note: Plugins already installed are skipped 27 | " 28 | exit 1 29 | else 30 | JENKINS_INPUT_JOB_LIST=$1 31 | if [ ! -f "$JENKINS_INPUT_JOB_LIST" ] 32 | then 33 | echo "ERROR File not found: $JENKINS_INPUT_JOB_LIST" 34 | exit 1 35 | fi 36 | fi 37 | 38 | # the war includes a # of plugins, to make the build efficient filter out 39 | # the plugins so we dont install 2x - there about 17! 40 | if [ -d "$JENKINS_HOME" ] 41 | then 42 | TEMP_ALREADY_INSTALLED=$JENKINS_HOME/preinstalled.plugins.$$.txt 43 | else 44 | echo "ERROR $JENKINS_HOME not found" 45 | exit 1 46 | fi 47 | 48 | JENKINS_PLUGINS_DIR=/var/jenkins_home/plugins 49 | if [ -d "$JENKINS_PLUGINS_DIR" ] 50 | then 51 | echo "Analyzing: $JENKINS_PLUGINS_DIR" 52 | for i in "$JENKINS_PLUGINS_DIR"/*/; do 53 | JENKINS_PLUGIN=$(basename "$i") 54 | JENKINS_PLUGIN_VER=$(grep -E -i Plugin-Version "$i/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //') 55 | echo "$JENKINS_PLUGIN:$JENKINS_PLUGIN_VER" 56 | done >"$TEMP_ALREADY_INSTALLED" 57 | else 58 | JENKINS_WAR=/usr/share/jenkins/jenkins.war 59 | if [ -f "$JENKINS_WAR" ] 60 | then 61 | echo "Analyzing war: $JENKINS_WAR" 62 | TEMP_PLUGIN_DIR=/tmp/plugintemp.$$ 63 | while read -r i <&3; do 64 | rm -fr "$TEMP_PLUGIN_DIR" 65 | mkdir -p "$TEMP_PLUGIN_DIR" 66 | PLUGIN=$(basename "$i"|cut -f1 -d'.') 67 | (cd "$TEMP_PLUGIN_DIR" || exit; jar xf "$JENKINS_WAR" "$i"; jar xvf "$TEMP_PLUGIN_DIR/$i" META-INF/MANIFEST.MF >/dev/null 2>&1) 68 | VER=$(grep -E -i Plugin-Version "$TEMP_PLUGIN_DIR/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //') 69 | echo "$PLUGIN:$VER" 70 | done 3< <(jar tf "$JENKINS_WAR" | grep -E '[^detached-]plugins.*\..pi' | sort) > "$TEMP_ALREADY_INSTALLED" 71 | rm -fr "$TEMP_PLUGIN_DIR" 72 | else 73 | rm -f "$TEMP_ALREADY_INSTALLED" 74 | echo "ERROR file not found: $JENKINS_WAR" 75 | exit 1 76 | fi 77 | fi 78 | 79 | REF=/usr/share/jenkins/ref/plugins 80 | mkdir -p $REF 81 | COUNT_PLUGINS_INSTALLED=0 82 | while read -r spec || [ -n "$spec" ]; do 83 | 84 | plugin=() 85 | IFS=' ' read -r -a plugin <<< "${spec//:/ }" 86 | [[ ${plugin[0]} =~ ^# ]] && continue 87 | [[ ${plugin[0]} =~ ^[[:space:]]*$ ]] && continue 88 | [[ -z ${plugin[1]} ]] && plugin[1]="latest" 89 | 90 | if [ -z "$JENKINS_UC_DOWNLOAD" ]; then 91 | JENKINS_UC_DOWNLOAD=$JENKINS_UC/download 92 | fi 93 | 94 | if ! grep -q "${plugin[0]}:${plugin[1]}" "$TEMP_ALREADY_INSTALLED" 95 | then 96 | echo "Downloading ${plugin[0]}:${plugin[1]}" 97 | curl --retry 3 --retry-delay 5 -sSL -f "${JENKINS_UC_DOWNLOAD}/plugins/${plugin[0]}/${plugin[1]}/${plugin[0]}.hpi" -o "$REF/${plugin[0]}.jpi" 98 | unzip -qqt "$REF/${plugin[0]}.jpi" 99 | (( COUNT_PLUGINS_INSTALLED += 1 )) 100 | else 101 | echo " ... skipping already installed: ${plugin[0]}:${plugin[1]}" 102 | fi 103 | done < "$JENKINS_INPUT_JOB_LIST" 104 | 105 | echo "---------------------------------------------------" 106 | if (( "$COUNT_PLUGINS_INSTALLED" > 0 )) 107 | then 108 | echo "INFO: Successfully installed $COUNT_PLUGINS_INSTALLED plugins." 109 | 110 | if [ -d $JENKINS_PLUGINS_DIR ] 111 | then 112 | echo "INFO: Please restart the container for changes to take effect!" 113 | fi 114 | else 115 | echo "INFO: No changes, all plugins previously installed." 116 | 117 | fi 118 | echo "---------------------------------------------------" 119 | 120 | #cleanup 121 | rm "$TEMP_ALREADY_INSTALLED" 122 | exit 0 -------------------------------------------------------------------------------- /tutorial_07/jenkins-master/plugins.txt: -------------------------------------------------------------------------------- 1 | jdk-tool 2 | jclouds-jenkins 3 | token-macro 4 | durable-task 5 | docker-plugin -------------------------------------------------------------------------------- /tutorial_07/jenkins-nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Install NGINX 5 | RUN yum -y update; yum clean all 6 | RUN yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm; yum -y makecache 7 | RUN yum -y install nginx-1.10.1 8 | 9 | # Remove default files we don't need 10 | RUN rm /etc/nginx/conf.d/default.conf 11 | 12 | # Add default configuration 13 | COPY conf/jenkins.conf /etc/nginx/conf.d/jenkins.conf 14 | COPY conf/nginx.conf /etc/nginx/nginx.conf 15 | 16 | EXPOSE 80 17 | 18 | CMD ["nginx"] -------------------------------------------------------------------------------- /tutorial_07/jenkins-nginx/conf/jenkins.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name ""; 4 | 5 | access_log off; 6 | 7 | location / { 8 | proxy_pass http://jenkins_master_1:8080; 9 | 10 | proxy_set_header Host $host; 11 | proxy_set_header X-Real-IP $remote_addr; 12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 13 | proxy_set_header X-Forwarded-Proto http; 14 | proxy_max_temp_file_size 0; 15 | 16 | proxy_connect_timeout 150; 17 | proxy_send_timeout 100; 18 | proxy_read_timeout 100; 19 | 20 | proxy_buffer_size 8k; 21 | proxy_buffers 4 32k; 22 | proxy_busy_buffers_size 64k; 23 | proxy_temp_file_write_size 64k; 24 | 25 | 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /tutorial_07/jenkins-nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | user nginx; 3 | worker_processes 2; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | use epoll; 12 | accept_mutex off; 13 | } 14 | 15 | 16 | http { 17 | include /etc/nginx/mime.types; 18 | proxy_set_header X-Real-IP $remote_addr; 19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | 21 | default_type application/octet-stream; 22 | 23 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 24 | '$status $body_bytes_sent "$http_referer" ' 25 | '"$http_user_agent" "$http_x_forwarded_for"'; 26 | 27 | access_log /var/log/nginx/access.log main; 28 | 29 | sendfile on; 30 | #tcp_nopush on; 31 | 32 | keepalive_timeout 65; 33 | 34 | client_max_body_size 300m; 35 | client_body_buffer_size 128k; 36 | 37 | gzip on; 38 | gzip_http_version 1.0; 39 | gzip_comp_level 6; 40 | gzip_min_length 0; 41 | gzip_buffers 16 8k; 42 | gzip_proxied any; 43 | gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json; 44 | gzip_disable "MSIE [1-6]\."; 45 | gzip_vary on; 46 | 47 | include /etc/nginx/conf.d/*.conf; 48 | } 49 | -------------------------------------------------------------------------------- /tutorial_07/jenkins-slave/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7 2 | LABEL maintainer="mstewart@riotgames.com" 3 | 4 | # Install Essentials 5 | RUN yum update -y && \ 6 | yum clean all 7 | 8 | # Install Packages 9 | RUN yum install -y git && \ 10 | yum install -y wget && \ 11 | yum install -y java-1.8.0-openjdk && \ 12 | yum install -y sudo && \ 13 | yum clean all 14 | 15 | ARG user=jenkins 16 | ARG group=jenkins 17 | ARG uid=1000 18 | ARG gid=1000 19 | 20 | ENV JENKINS_HOME /home/${user} 21 | 22 | # Jenkins is run with user `jenkins`, uid = 1000 23 | RUN groupadd -g ${gid} ${group} \ 24 | && useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user} 25 | 26 | RUN chown -R ${user}:${user} /home/${user} 27 | 28 | # Add the jenkins user to sudoers 29 | RUN echo "${user} ALL=(ALL) ALL" >> etc/sudoers 30 | 31 | # Set Name Servers 32 | COPY /files/resolv.conf /etc/resolv.conf 33 | 34 | -------------------------------------------------------------------------------- /tutorial_07/jenkins-slave/files/resolv.conf: -------------------------------------------------------------------------------- 1 | nameserver 8.8.8.8 2 | nameserver 8.8.4.4 3 | -------------------------------------------------------------------------------- /tutorial_07/makefile: -------------------------------------------------------------------------------- 1 | build: 2 | @docker-compose -p jenkins build 3 | run: 4 | @docker-compose -p jenkins up -d nginx master proxy 5 | run-win: 6 | @docker-compose -p jenkins up -d nginx master 7 | stop: 8 | @docker-compose -p jenkins down 9 | clean-data: 10 | @docker-compose -p jenkins down -v 11 | clean-images: 12 | @docker rmi `docker images -q -f "dangling=true"` 13 | ps: 14 | @docker-compose -p jenkins ps 15 | jenkins-log: 16 | @docker-compose -p jenkins exec master tail -f /var/log/jenkins/jenkins.log 17 | 18 | --------------------------------------------------------------------------------