blob: 2ef412949297225830b1a89db6f23d17474afff2 [file] [log] [blame]
Alanny Lopez620baa12017-10-10 11:50:03 -05001#!/bin/bash
2################################################################################
Alanny Lopeze08e8702018-02-24 18:07:13 -06003#
Alanny Lopez620baa12017-10-10 11:50:03 -05004# Script used to create a Jenkins master that can run amd64 or ppc64le. It can
5# be used to launch the Jenkins master as a Docker container locally or as a
6# Kubernetes Deployment in a Kubernetes cluster.
Alanny Lopeze08e8702018-02-24 18:07:13 -06007#
Alanny Lopez620baa12017-10-10 11:50:03 -05008################################################################################
Alanny Lopeze08e8702018-02-24 18:07:13 -06009#
10# Script Variables:
11# build_scripts_dir The path of the openbmc-build-scripts directory.
12# Default: The directory containing this script
13# workspace The directory that holds files used to build the Jenkins
14# master master image and volumes used to deploy it.
15# Default: "~/jenkins-build-${RANDOM}"
16#
17# Jenkins Dockerfile Variables:
18# agent_port The port used as the Jenkins slave agent port.
19# Default: "50000"
20# http_port The port used as Jenkins UI port.
21# Default: "8080"
Alanny Lopez1246b032018-02-24 23:34:55 -060022# img_name The name given to the Docker image when it is built.
Alanny Lopeze08e8702018-02-24 18:07:13 -060023# Default: "openbmc/jenkins-master-${ARCH}:${JENKINS_VRSN}"
Alanny Lopez46967702018-02-25 00:29:14 -060024# img_tag The tag of the OpenJDK image used as the base image.
25# Default: "/8-jdk"
26# j_gid Jenkins group ID the container will use to run Jenkins.
27# Default: "1000"
28# j_group Group name tag the container will use to run Jenkins.
29# Default: "jenkins"
30# j_home Directory used as the Jenkins Home in the container.
31# Default: "/var/jenkins_home"
32# j_uid Jenkins user ID the container will use to run Jenkins.
33# Default: "1000"
34# j_user Username tag the container will use to run Jenkins.
35# Default: "jenkins"
36# j_vrsn The version of the Jenkins war file you wish to use.
37# Default: "2.60.3"
Alanny Lopeze08e8702018-02-24 18:07:13 -060038# tini_vrsn The version of Tini to use in the Dockerfile, 0.16.1 is
39# the first release with ppc64le release support.
40# Default: "0.16.1"
41#
42# Deployment Variables:
43# cont_import_mnt The directory on the container used to import extra files.
44# Default: "/mnt/jenkins_import", ignored if above not set
45# home_mnt The directory on the host used as the Jenkins home.
Alanny Lopez620baa12017-10-10 11:50:03 -050046# Default: "${WORKSPACE}/jenkins_home"
Alanny Lopeze08e8702018-02-24 18:07:13 -060047# host_import_mnt The directory on the host used to import extra files.
48# Default: "", import mount is ignored if not set
Alanny Lopez492c52c2017-11-10 15:06:26 -060049# java_options What will be passed as the environment variable for the
50# JAVA_OPTS environment variable.
51# Default: "-Xmx4096m"
Alanny Lopez46967702018-02-25 00:29:14 -060052# jenkins_options What will be passed as the environment variable for the
53# JENKINS_OPTS environment variable.
54# Default: "--prefix=/jenkins"
Alanny Lopeze08e8702018-02-24 18:07:13 -060055# launch docker|k8s
56# Method in which the container will be launched. Either as
57# a Docker container launched via Docker, or by using a
58# helper script to launch into a Kubernetes cluster.
59# Default: "docker"
Alanny Lopez620baa12017-10-10 11:50:03 -050060#
61################################################################################
Alanny Lopez620baa12017-10-10 11:50:03 -050062set -xeo pipefail
63ARCH=$(uname -m)
64
Alanny Lopez46967702018-02-25 00:29:14 -060065# Script Variables
66build_scripts_dir=${build_scripts_dir:-"$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"}
Alanny Lopez620baa12017-10-10 11:50:03 -050067workspace=${workspace:-${HOME}/jenkins-build-${RANDOM}}
Alanny Lopez620baa12017-10-10 11:50:03 -050068
Alanny Lopez46967702018-02-25 00:29:14 -060069# Jenkins Dockerfile Variables
70agent_port=${agent_port:-50000}
71http_port=${http_port:-8080}
72img_name=${img_name:-openbmc/jenkins-master-${ARCH}:${j_vrsn}}
73j_gid=${j_gid:-1000}
74j_group=${j_group:-jenkins}
75j_home=${j_home:-/var/jenkins_home}
76j_uid=${j_uid:-1000}
77j_user=${j_user:-jenkins}
78j_vrsn=${j_vrsn:-2.60.3}
Alanny Lopez620baa12017-10-10 11:50:03 -050079img_tag=${img_tag:-8-jdk}
80tini_vrsn=${tini_vrsn:-0.16.1}
Alanny Lopez46967702018-02-25 00:29:14 -060081
82# Deployment Variables
83cont_import_mnt=${cont_import_mnt:-/mnt/jenkins_import}
84home_mnt=${home_mnt:-${workspace}/jenkins_home}
85host_import_mnt=${host_import_mnt:-}
86java_options=${java_options:-"-Xmx4096m"}
87jenkins_options=${jenkins_options:-"--prefix=/jenkins"}
88launch=${launch:-docker}
Alanny Lopez620baa12017-10-10 11:50:03 -050089
90# Save the Jenkins.war URL to a variable and SHA if we care about verification
91j_url=https://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/${j_vrsn}/jenkins-war-${j_vrsn}.war
92
93# Make or Clean WORKSPACE
Patrick Williams384d7412020-11-06 16:15:41 -060094if [[ -d "${workspace}" ]]; then
95 rm -rf "${workspace}/Dockerfile" \
96 "${workspace}/docker-jenkins" \
97 "${workspace}/plugins.*" \
98 "${workspace}/install-plugins.sh" \
99 "${workspace}/jenkins.sh" \
100 "${workspace}/jenkins-support" \
101 "${workspace}/init.groovy"
Alanny Lopez620baa12017-10-10 11:50:03 -0500102else
Patrick Williams384d7412020-11-06 16:15:41 -0600103 mkdir -p "${workspace}"
Alanny Lopez620baa12017-10-10 11:50:03 -0500104fi
105
106# Determine the prefix of the Dockerfile's base image
107case ${ARCH} in
108 "ppc64le")
109 docker_base="ppc64le/"
110 tini_arch="ppc64el"
111 ;;
112 "x86_64")
113 docker_base=""
114 tini_arch="amd64"
115 ;;
Thang Q. Nguyen051b05b2021-12-10 08:30:35 +0000116 "aarch64")
117 docker_base=""
118 tini_arch="arm64"
119 ;;
Alanny Lopez620baa12017-10-10 11:50:03 -0500120 *)
121 echo "Unsupported system architecture(${ARCH}) found for docker image"
122 exit 1
123esac
124
125# Move Into the WORKSPACE
Patrick Williams384d7412020-11-06 16:15:41 -0600126cd "${workspace}"
Alanny Lopez620baa12017-10-10 11:50:03 -0500127
128# Make the Dockerfile
129################################################################################
130cat >> Dockerfile << EOF
131FROM ${docker_base}openjdk:${img_tag}
132
133RUN apt-get update && apt-get install -y git curl
134
135ENV JENKINS_HOME ${j_home}
136ENV JENKINS_SLAVE_AGENT_PORT ${agent_port}
137
Alanny Lopez492c52c2017-11-10 15:06:26 -0600138# Jenkins will default to run with user jenkins, uid = 1000
Alanny Lopez620baa12017-10-10 11:50:03 -0500139# If you bind mount a volume from the host or a data container,
140# ensure you use the same uid
141RUN groupadd -g ${j_gid} ${j_group} && \
142 useradd -d ${j_home} -u ${j_uid} -g ${j_gid} -m -s /bin/bash ${j_user}
143
144# Jenkins home directory is a volume, so configuration and build history
145# can be persisted and survive image upgrades
146VOLUME ${j_home}
147
Alanny Lopez492c52c2017-11-10 15:06:26 -0600148# /usr/share/jenkins/ref/ contains all reference configuration we want
Alanny Lopez620baa12017-10-10 11:50:03 -0500149# to set on a fresh new installation. Use it to bundle additional plugins
150# or config file with your custom jenkins Docker image.
151RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d
152
153# Use tini as subreaper in Docker container to adopt zombie processes
154RUN curl -fsSL https://github.com/krallin/tini/releases/download/v${tini_vrsn}/tini-static-${tini_arch} \
155 -o /bin/tini && \
156 chmod +x /bin/tini
157
158COPY init.groovy /usr/share/jenkins/ref/init.groovy.d/tcp-slave-agent-port.groovy
159
160# could use ADD but this one does not check Last-Modified header neither does it allow to control checksum
161# see https://github.com/docker/docker/issues/8331
162RUN curl -fsSL ${j_url} -o /usr/share/jenkins/jenkins.war
163
164ENV JENKINS_UC https://updates.jenkins.io
165ENV JENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimental
166RUN chown -R ${j_user} ${j_home} /usr/share/jenkins/ref
167
168# for main web interface:
169EXPOSE ${http_port}
170
171# will be used by attached slave agents:
172EXPOSE ${agent_port}
173
174ENV COPY_REFERENCE_FILE_LOG ${j_home}/copy_reference_file.log
175USER ${j_user}
176
177COPY jenkins-support /usr/local/bin/jenkins-support
178COPY jenkins.sh /usr/local/bin/jenkins.sh
179ENTRYPOINT ["/bin/tini", "--", "/usr/local/bin/jenkins.sh"]
180
Alanny Lopez492c52c2017-11-10 15:06:26 -0600181# from a derived Dockerfile, can use RUN plugins.sh active.txt to setup /usr/share/jenkins/ref/plugins from a support bundle
Alanny Lopez620baa12017-10-10 11:50:03 -0500182COPY plugins.sh /usr/local/bin/plugins.sh
183COPY install-plugins.sh /usr/local/bin/install-plugins.sh
184
185# Install plugins.txt plugins
186COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
187RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt
188EOF
189################################################################################
190
191# Clone in the jenkinsci docker jenkins repo and copy some files into WORKSPACE
192git clone https://github.com/jenkinsci/docker.git docker-jenkins
193cp docker-jenkins/init.groovy .
194cp docker-jenkins/jenkins-support .
195cp docker-jenkins/jenkins.sh .
196cp docker-jenkins/plugins.sh .
197cp docker-jenkins/install-plugins.sh .
198
199# Generate Plugins.txt, the plugins you want installed automatically go here
200################################################################################
201cat >> plugins.txt << EOF
202kubernetes
203EOF
204################################################################################
205
206# Build the image
Patrick Williams384d7412020-11-06 16:15:41 -0600207docker build -t "${img_name}" .
Alanny Lopez620baa12017-10-10 11:50:03 -0500208
Patrick Williams384d7412020-11-06 16:15:41 -0600209if [[ "${launch}" == "docker" ]]; then
Alanny Lopez620baa12017-10-10 11:50:03 -0500210
211 # Ensure directories that will be mounted exist
Patrick Williams384d7412020-11-06 16:15:41 -0600212 if [[ -n "${host_import_mnt}" && ! -d "${host_import_mnt}" ]]; then
213 mkdir -p "${host_import_mnt}"
Alanny Lopez620baa12017-10-10 11:50:03 -0500214 fi
Alanny Lopez29cc3b12017-10-18 15:18:00 -0500215
Patrick Williams384d7412020-11-06 16:15:41 -0600216 if [[ ! -d "${home_mnt}" ]]; then
217 mkdir -p "${home_mnt}"
Alanny Lopez620baa12017-10-10 11:50:03 -0500218 fi
219
George Keishing11a6e9e2019-07-22 08:18:40 -0500220 # Ensure directories that will be mounted are owned by the jenkins user
Alanny Lopez620baa12017-10-10 11:50:03 -0500221 if [[ "$(id -u)" != 0 ]]; then
222 echo "Not running as root:"
Alanny Lopez1246b032018-02-24 23:34:55 -0600223 echo "Checking if j_gid and j_uid are the owners of mounted directories"
Patrick Williams384d7412020-11-06 16:15:41 -0600224 # shellcheck disable=SC2012 # use ls to get permissions.
225 test_1="$(ls -nd "${home_mnt}" | awk '{print $3 " " $4}')"
Alanny Lopez1246b032018-02-24 23:34:55 -0600226 if [[ "${test_1}" != "${j_uid} ${j_gid}" ]]; then
Alanny Lopez620baa12017-10-10 11:50:03 -0500227 echo "Owner of ${home_mnt} is not the jenkins user"
Alanny Lopez1246b032018-02-24 23:34:55 -0600228 echo "${test_1} != ${j_uid} ${j_gid}"
229 will_fail=1
Alanny Lopez620baa12017-10-10 11:50:03 -0500230 fi
Patrick Williams384d7412020-11-06 16:15:41 -0600231 if [[ -n "${host_import_mnt}" ]]; then
232 # shellcheck disable=SC2012 # use ls to get permissions.
233 test_2="$(ls -nd "${host_import_mnt}" | awk '{print $3 " " $4}' )"
Alanny Lopez1246b032018-02-24 23:34:55 -0600234 if [[ "${test_2}" != "${j_uid} ${j_gid}" ]]; then
Alanny Lopez29cc3b12017-10-18 15:18:00 -0500235 echo "Owner of ${host_import_mnt} is not the jenkins user"
Alanny Lopez1246b032018-02-24 23:34:55 -0600236 echo "${test_2} != ${j_uid} ${j_gid}"
237 will_fail=1
Alanny Lopez29cc3b12017-10-18 15:18:00 -0500238 fi
Alanny Lopez620baa12017-10-10 11:50:03 -0500239 fi
Alanny Lopez1246b032018-02-24 23:34:55 -0600240 if [[ "${will_fail}" == 1 ]]; then
Alanny Lopez620baa12017-10-10 11:50:03 -0500241 echo "Failing before attempting to launch container"
242 echo "Try again as root or use correct uid/gid pairs"
243 exit 1
244 fi
245 else
Patrick Williams384d7412020-11-06 16:15:41 -0600246 if [[ -n "${host_import_mnt}" ]]; then
247 chown -R "${j_uid}:${j_gid}" "${host_import_mnt}"
Alanny Lopez29cc3b12017-10-18 15:18:00 -0500248 fi
Patrick Williams384d7412020-11-06 16:15:41 -0600249 chown -R "${j_uid}:${j_gid}" "${home_mnt}"
Alanny Lopez620baa12017-10-10 11:50:03 -0500250 fi
251
Alanny Lopez29cc3b12017-10-18 15:18:00 -0500252 #If we don't have import mount don't add to docker command
Patrick Williams384d7412020-11-06 16:15:41 -0600253 if [[ -n "${host_import_mnt}" ]]; then
Alanny Lopez1246b032018-02-24 23:34:55 -0600254 import_vol_cmd="-v ${host_import_mnt}:${cont_import_mnt}"
Alanny Lopez29cc3b12017-10-18 15:18:00 -0500255 fi
Alanny Lopez620baa12017-10-10 11:50:03 -0500256 # Launch the jenkins image with Docker
Patrick Williams384d7412020-11-06 16:15:41 -0600257 # shellcheck disable=SC2086 # import_vol_cmd is intentially word-split.
Alanny Lopez620baa12017-10-10 11:50:03 -0500258 docker run -d \
Alanny Lopez1246b032018-02-24 23:34:55 -0600259 ${import_vol_cmd} \
Patrick Williams384d7412020-11-06 16:15:41 -0600260 -v "${home_mnt}:${j_home}" \
261 -p "${http_port}:8080" \
262 -p "${agent_port}:${agent_port}" \
263 --env JAVA_OPTS=\""${java_options}"\" \
264 --env JENKINS_OPTS=\""${jenkins_options}"\" \
265 "${img_name}"
Alanny Lopez620baa12017-10-10 11:50:03 -0500266
Alanny Lopez29cc3b12017-10-18 15:18:00 -0500267fi