Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | ################################################################################ |
Alanny Lopez | e08e870 | 2018-02-24 18:07:13 -0600 | [diff] [blame] | 3 | # |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 4 | # 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 Lopez | e08e870 | 2018-02-24 18:07:13 -0600 | [diff] [blame] | 7 | # |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 8 | ################################################################################ |
Alanny Lopez | e08e870 | 2018-02-24 18:07:13 -0600 | [diff] [blame] | 9 | # |
| 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 Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 22 | # img_name The name given to the Docker image when it is built. |
Alanny Lopez | e08e870 | 2018-02-24 18:07:13 -0600 | [diff] [blame] | 23 | # Default: "openbmc/jenkins-master-${ARCH}:${JENKINS_VRSN}" |
Alanny Lopez | 4696770 | 2018-02-25 00:29:14 -0600 | [diff] [blame] | 24 | # 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 Lopez | e08e870 | 2018-02-24 18:07:13 -0600 | [diff] [blame] | 38 | # 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 Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 46 | # Default: "${WORKSPACE}/jenkins_home" |
Alanny Lopez | e08e870 | 2018-02-24 18:07:13 -0600 | [diff] [blame] | 47 | # host_import_mnt The directory on the host used to import extra files. |
| 48 | # Default: "", import mount is ignored if not set |
Alanny Lopez | 492c52c | 2017-11-10 15:06:26 -0600 | [diff] [blame] | 49 | # java_options What will be passed as the environment variable for the |
| 50 | # JAVA_OPTS environment variable. |
| 51 | # Default: "-Xmx4096m" |
Alanny Lopez | 4696770 | 2018-02-25 00:29:14 -0600 | [diff] [blame] | 52 | # jenkins_options What will be passed as the environment variable for the |
| 53 | # JENKINS_OPTS environment variable. |
| 54 | # Default: "--prefix=/jenkins" |
Alanny Lopez | e08e870 | 2018-02-24 18:07:13 -0600 | [diff] [blame] | 55 | # 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 Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 60 | # |
| 61 | ################################################################################ |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 62 | set -xeo pipefail |
| 63 | ARCH=$(uname -m) |
| 64 | |
Alanny Lopez | 4696770 | 2018-02-25 00:29:14 -0600 | [diff] [blame] | 65 | # Script Variables |
| 66 | build_scripts_dir=${build_scripts_dir:-"$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"} |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 67 | workspace=${workspace:-${HOME}/jenkins-build-${RANDOM}} |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 68 | |
Alanny Lopez | 4696770 | 2018-02-25 00:29:14 -0600 | [diff] [blame] | 69 | # Jenkins Dockerfile Variables |
| 70 | agent_port=${agent_port:-50000} |
| 71 | http_port=${http_port:-8080} |
| 72 | img_name=${img_name:-openbmc/jenkins-master-${ARCH}:${j_vrsn}} |
| 73 | j_gid=${j_gid:-1000} |
| 74 | j_group=${j_group:-jenkins} |
| 75 | j_home=${j_home:-/var/jenkins_home} |
| 76 | j_uid=${j_uid:-1000} |
| 77 | j_user=${j_user:-jenkins} |
| 78 | j_vrsn=${j_vrsn:-2.60.3} |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 79 | img_tag=${img_tag:-8-jdk} |
| 80 | tini_vrsn=${tini_vrsn:-0.16.1} |
Alanny Lopez | 4696770 | 2018-02-25 00:29:14 -0600 | [diff] [blame] | 81 | |
| 82 | # Deployment Variables |
| 83 | cont_import_mnt=${cont_import_mnt:-/mnt/jenkins_import} |
| 84 | home_mnt=${home_mnt:-${workspace}/jenkins_home} |
| 85 | host_import_mnt=${host_import_mnt:-} |
| 86 | java_options=${java_options:-"-Xmx4096m"} |
| 87 | jenkins_options=${jenkins_options:-"--prefix=/jenkins"} |
| 88 | launch=${launch:-docker} |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 89 | |
| 90 | # Save the Jenkins.war URL to a variable and SHA if we care about verification |
| 91 | j_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 Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 94 | if [[ -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 Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 102 | else |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 103 | mkdir -p "${workspace}" |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 104 | fi |
| 105 | |
| 106 | # Determine the prefix of the Dockerfile's base image |
| 107 | case ${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. Nguyen | 051b05b | 2021-12-10 08:30:35 +0000 | [diff] [blame^] | 116 | "aarch64") |
| 117 | docker_base="" |
| 118 | tini_arch="arm64" |
| 119 | ;; |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 120 | *) |
| 121 | echo "Unsupported system architecture(${ARCH}) found for docker image" |
| 122 | exit 1 |
| 123 | esac |
| 124 | |
| 125 | # Move Into the WORKSPACE |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 126 | cd "${workspace}" |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 127 | |
| 128 | # Make the Dockerfile |
| 129 | ################################################################################ |
| 130 | cat >> Dockerfile << EOF |
| 131 | FROM ${docker_base}openjdk:${img_tag} |
| 132 | |
| 133 | RUN apt-get update && apt-get install -y git curl |
| 134 | |
| 135 | ENV JENKINS_HOME ${j_home} |
| 136 | ENV JENKINS_SLAVE_AGENT_PORT ${agent_port} |
| 137 | |
Alanny Lopez | 492c52c | 2017-11-10 15:06:26 -0600 | [diff] [blame] | 138 | # Jenkins will default to run with user jenkins, uid = 1000 |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 139 | # If you bind mount a volume from the host or a data container, |
| 140 | # ensure you use the same uid |
| 141 | RUN 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 |
| 146 | VOLUME ${j_home} |
| 147 | |
Alanny Lopez | 492c52c | 2017-11-10 15:06:26 -0600 | [diff] [blame] | 148 | # /usr/share/jenkins/ref/ contains all reference configuration we want |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 149 | # to set on a fresh new installation. Use it to bundle additional plugins |
| 150 | # or config file with your custom jenkins Docker image. |
| 151 | RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d |
| 152 | |
| 153 | # Use tini as subreaper in Docker container to adopt zombie processes |
| 154 | RUN 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 | |
| 158 | COPY 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 |
| 162 | RUN curl -fsSL ${j_url} -o /usr/share/jenkins/jenkins.war |
| 163 | |
| 164 | ENV JENKINS_UC https://updates.jenkins.io |
| 165 | ENV JENKINS_UC_EXPERIMENTAL=https://updates.jenkins.io/experimental |
| 166 | RUN chown -R ${j_user} ${j_home} /usr/share/jenkins/ref |
| 167 | |
| 168 | # for main web interface: |
| 169 | EXPOSE ${http_port} |
| 170 | |
| 171 | # will be used by attached slave agents: |
| 172 | EXPOSE ${agent_port} |
| 173 | |
| 174 | ENV COPY_REFERENCE_FILE_LOG ${j_home}/copy_reference_file.log |
| 175 | USER ${j_user} |
| 176 | |
| 177 | COPY jenkins-support /usr/local/bin/jenkins-support |
| 178 | COPY jenkins.sh /usr/local/bin/jenkins.sh |
| 179 | ENTRYPOINT ["/bin/tini", "--", "/usr/local/bin/jenkins.sh"] |
| 180 | |
Alanny Lopez | 492c52c | 2017-11-10 15:06:26 -0600 | [diff] [blame] | 181 | # from a derived Dockerfile, can use RUN plugins.sh active.txt to setup /usr/share/jenkins/ref/plugins from a support bundle |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 182 | COPY plugins.sh /usr/local/bin/plugins.sh |
| 183 | COPY install-plugins.sh /usr/local/bin/install-plugins.sh |
| 184 | |
| 185 | # Install plugins.txt plugins |
| 186 | COPY plugins.txt /usr/share/jenkins/ref/plugins.txt |
| 187 | RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt |
| 188 | EOF |
| 189 | ################################################################################ |
| 190 | |
| 191 | # Clone in the jenkinsci docker jenkins repo and copy some files into WORKSPACE |
| 192 | git clone https://github.com/jenkinsci/docker.git docker-jenkins |
| 193 | cp docker-jenkins/init.groovy . |
| 194 | cp docker-jenkins/jenkins-support . |
| 195 | cp docker-jenkins/jenkins.sh . |
| 196 | cp docker-jenkins/plugins.sh . |
| 197 | cp docker-jenkins/install-plugins.sh . |
| 198 | |
| 199 | # Generate Plugins.txt, the plugins you want installed automatically go here |
| 200 | ################################################################################ |
| 201 | cat >> plugins.txt << EOF |
| 202 | kubernetes |
| 203 | EOF |
| 204 | ################################################################################ |
| 205 | |
| 206 | # Build the image |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 207 | docker build -t "${img_name}" . |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 208 | |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 209 | if [[ "${launch}" == "docker" ]]; then |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 210 | |
| 211 | # Ensure directories that will be mounted exist |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 212 | if [[ -n "${host_import_mnt}" && ! -d "${host_import_mnt}" ]]; then |
| 213 | mkdir -p "${host_import_mnt}" |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 214 | fi |
Alanny Lopez | 29cc3b1 | 2017-10-18 15:18:00 -0500 | [diff] [blame] | 215 | |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 216 | if [[ ! -d "${home_mnt}" ]]; then |
| 217 | mkdir -p "${home_mnt}" |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 218 | fi |
| 219 | |
George Keishing | 11a6e9e | 2019-07-22 08:18:40 -0500 | [diff] [blame] | 220 | # Ensure directories that will be mounted are owned by the jenkins user |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 221 | if [[ "$(id -u)" != 0 ]]; then |
| 222 | echo "Not running as root:" |
Alanny Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 223 | echo "Checking if j_gid and j_uid are the owners of mounted directories" |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 224 | # shellcheck disable=SC2012 # use ls to get permissions. |
| 225 | test_1="$(ls -nd "${home_mnt}" | awk '{print $3 " " $4}')" |
Alanny Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 226 | if [[ "${test_1}" != "${j_uid} ${j_gid}" ]]; then |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 227 | echo "Owner of ${home_mnt} is not the jenkins user" |
Alanny Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 228 | echo "${test_1} != ${j_uid} ${j_gid}" |
| 229 | will_fail=1 |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 230 | fi |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 231 | 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 Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 234 | if [[ "${test_2}" != "${j_uid} ${j_gid}" ]]; then |
Alanny Lopez | 29cc3b1 | 2017-10-18 15:18:00 -0500 | [diff] [blame] | 235 | echo "Owner of ${host_import_mnt} is not the jenkins user" |
Alanny Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 236 | echo "${test_2} != ${j_uid} ${j_gid}" |
| 237 | will_fail=1 |
Alanny Lopez | 29cc3b1 | 2017-10-18 15:18:00 -0500 | [diff] [blame] | 238 | fi |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 239 | fi |
Alanny Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 240 | if [[ "${will_fail}" == 1 ]]; then |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 241 | 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 Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 246 | if [[ -n "${host_import_mnt}" ]]; then |
| 247 | chown -R "${j_uid}:${j_gid}" "${host_import_mnt}" |
Alanny Lopez | 29cc3b1 | 2017-10-18 15:18:00 -0500 | [diff] [blame] | 248 | fi |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 249 | chown -R "${j_uid}:${j_gid}" "${home_mnt}" |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 250 | fi |
| 251 | |
Alanny Lopez | 29cc3b1 | 2017-10-18 15:18:00 -0500 | [diff] [blame] | 252 | #If we don't have import mount don't add to docker command |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 253 | if [[ -n "${host_import_mnt}" ]]; then |
Alanny Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 254 | import_vol_cmd="-v ${host_import_mnt}:${cont_import_mnt}" |
Alanny Lopez | 29cc3b1 | 2017-10-18 15:18:00 -0500 | [diff] [blame] | 255 | fi |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 256 | # Launch the jenkins image with Docker |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 257 | # shellcheck disable=SC2086 # import_vol_cmd is intentially word-split. |
Alanny Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 258 | docker run -d \ |
Alanny Lopez | 1246b03 | 2018-02-24 23:34:55 -0600 | [diff] [blame] | 259 | ${import_vol_cmd} \ |
Patrick Williams | 384d741 | 2020-11-06 16:15:41 -0600 | [diff] [blame] | 260 | -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 Lopez | 620baa1 | 2017-10-10 11:50:03 -0500 | [diff] [blame] | 266 | |
Alanny Lopez | 29cc3b1 | 2017-10-18 15:18:00 -0500 | [diff] [blame] | 267 | fi |