「Jenkins」- 安装 | 升级 | CentOS | Debian | Ubuntu

该笔记将记录:与 Jenkins 安装、升级有关的内容,以及相关问题的解决办法;

on Linux | with Package Manager

Installing Jenkins/Linux

依赖安装

安装 JDK/JRE 包(Jenkins 使用 Java 开发的,需要安装运行环境):

# Debian GNU/Linux 10 (buster)
apt-get install -y openjdk-11-jre

on Ubuntu 20.04

Installing Jenkins/Linux

Weekly release:

curl -fsSL https://pkg.jenkins.io/debian/jenkins.io.key | sudo tee \
  /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
  https://pkg.jenkins.io/debian binary/ | sudo tee \
  /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install jenkins

on CentOS 7.0

RedHat Linux RPM packages for Jenkins

# 12/27/2018

yum install wget
yum install java-1.8.0-openjdk.x86_64

wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo
rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key

yum install jenkins

访问服务器地址,开始配置你的的 Jenkins,首页是让你输入初始密码,并告诉你初时密码所在的文件;

on Debian 10

Debian Jenkins Packages

Jenkins Regular releases (Weekly)

# 08/19/2020

wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | apt-key add -
echo 'deb https://pkg.jenkins.io/debian binary/' > /etc/apt/sources.list.d/jenkins.list
apt-get update

apt-get install -y jenkins
/lib/systemd/systemd-sysv-install enable jenkins
systemctl start jenkins.service

# 浏览器访问 http://127.0.0.1:8080 以进行初始化

on Debian 8.2

Debian/Ubuntu

# 04/04/2019

wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | apt-key add -
echo "deb http://pkg.jenkins.io/debian-stable binary/" > /etc/apt/sources.list.d/jenkins.list

apt-get update
apt-get install -y jenkins

# 如果你要手动指定自己的 JDK 版
# 修改 /etc/default/jenkin 文件,追加如下行在开始
JAVA_HOME="/opt/openjdk-1.8"
PATH="$JAVA_HOME/bin:$PATH"

反向代理 | 通过 Nginx 暴露

Jenkins 配置为 Nginx 的后端代理
Running Jenkins behind Nginx
Hide a client request header with a Nginx reverse proxy server

参考 Running Jenkins behind Nginx 文档,以获取官方对反向代理的详细说明;

下面是配置文件(直接复制自官方,我们并未深入研究):

upstream jenkins {
  keepalive 32; # keepalive connections
  server 127.0.0.1:8080; # jenkins ip and port
}

server {
  listen          80;       # Listen on port 80 for IPv4 requests

  server_name     jenkins.example.com;

  #this is the jenkins web root directory (mentioned in the /etc/default/jenkins file)
  root            /var/run/jenkins/war/;

  access_log      /var/log/nginx/jenkins/access.log;
  error_log       /var/log/nginx/jenkins/error.log;
  ignore_invalid_headers off; #pass through headers from Jenkins which are considered invalid by Nginx server.

  location ~ "^/static/[0-9a-fA-F]{8}\/(.*)$" {
    #rewrite all static files into requests to the root
    #E.g /static/12345678/css/something.css will become /css/something.css
    rewrite "^/static/[0-9a-fA-F]{8}\/(.*)" /$1 last;
  }

  location /userContent {
    #have nginx handle all the static requests to the userContent folder files
    #note : This is the $JENKINS_HOME dir
	root /var/lib/jenkins/;
    if (!-f $request_filename){
      #this file does not exist, might be a directory or a /**view** url
      rewrite (.*) /$1 last;
	  break;
    }
	sendfile on;
  }

  location / {
      sendfile off;
      proxy_pass         http://jenkins;
      proxy_redirect     default;
      proxy_http_version 1.1;

      proxy_set_header   Host              $host;
      proxy_set_header   X-Real-IP         $remote_addr;
      proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header   X-Forwarded-Proto $scheme;
      proxy_max_temp_file_size 0;

      #this is the maximum upload size
      client_max_body_size       10m;
      client_body_buffer_size    128k;

      proxy_connect_timeout      90;
      proxy_send_timeout         90;
      proxy_read_timeout         90;
      proxy_buffering            off;
      proxy_request_buffering    off; # Required for HTTP CLI commands in Jenkins > 2.54
      proxy_set_header Connection ""; # Clear for keepalive
  }

}

on Docker | with Docker Compose | Jenkins 2.502-jdk17

docker pull jenkins/jenkins:2.502-jdk17 # openjdk 17.0.14

on Kubernetes | with Helm Chart

2.346.1 | on Kubernetes | with Helm Chart by Official

Jenkins on Kubernetes Engine

该笔记将记录:在 Kubernetes Cluster 中,如何部署 Jenkins 服务,重点将现有 Jenkins 服务迁移到 Kubernetes 中;

注 1:鉴于迁移是我们的重点工作,所以部署过程会涉及迁移相关的内容;

# 添加仓库
helm repo add jenkinsci https://charts.jenkins.io
helm repo update
helm search repo jenkinsci

# 下载
# 我们 Jenkins 2.345 版本,但是没有该版本的 Chart 资源,
# 而 4.1.12 对应 Jenkins 2.346.1 版本,最贴近(算是微小升级);
helm pull jenkinsci/jenkins --version 4.1.12                                    # jenkins-4.1.12.tgz

# 修改配置
helm show values ./jenkins-4.1.12.tgz > jenkins-4.1.12.helm-values.yaml
...(1)修改 storageClass 参数,以配置其使用的存储类;
...(2)修改 Ingress 参数,以保留服务提供 HTTP 访问;

# 服务部署
helm --namespace jenkins                                                       \
    install jenkins ./jenkins-4.1.12.tgz -f jenkins-4.1.12.helm-values.yaml    \
    --create-namespace

# 查看密码
kubectl exec --namespace jenkins -it svc/jenkins -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo

# 服务登录
# admin:<password>

服务迁移:Docker Compose ⇒ Kubernetes

Kubernetes/Jenkins

问题描述

在 Kubernetes 大为流行前,我们已经开始使用 Jenkins 服务,现在我们需要将 Jenkins 迁移到 Kubernetes 环境,而非重新部署 Jenkins 服务;

解决方案

目前(07/10/2022),我们的想法是:
1)首先,运行 rsync 容器,并创建 PV 与 PVC 资源,负责将数据复制到 PV 内;
2)在启动 Jenkins 服务,并在其中引用该 PVC 资源,并检查 Jenins 能够正常运行;

接下来是验证工作:

第一步、数据迁移

运行 rsync 容器,并完成数据同步:

kubectl apply -f - <<EOF
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: jenkins-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 100Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: jenkins-migration
spec:
  volumes:
    - name: jenkins-claim
      persistentVolumeClaim:
        claimName: jenkins-claim
  containers:
    - name: rsync
      image: eeacms/rsync
      command: ["sleep", "infinity"]
      volumeMounts:
        - mountPath: "/srv/jenkins/"
          name: jenkins-claim
EOF

# 进行数据同步
kubectl exec -it jenkins-migration -- sh
rsync --delete -avz root@jenkins-old:/var/lib/jenkins/ /srv/jenkins/

第二步、创建 Jenkins 服务

按照前述步骤,通过 Helm 部署 Jenkins 服务:
1)修改 persistence.existingClaim: jenkins-claim 参数,以使用已创建的 PVC 资源;
2)修改 Ingress 配置,以暴露 Jenkins 服务;
3)最后,通过 Helm 进行部署(当启动时会自动下载安装部分插件,所以稍慢);

第三步、访问验证,问题修复

浏览器访问 Jenkins 服务,并检查是否正常运行,是否存在异常;
部分问题的出现,其与多种因素(诸如场景、版本、插件等等)相关,我们将描述我们遇到的问题。

针对插件依赖错误问题:
1)当迁移到 Kubernets 环境后,鉴于 Jenkins 版本未与原始版本完全匹配,外加某些未知因素,导致插件依赖出现问题。
2)按照提示,我们依次更新 Jackson 2 API Plugin、SnakeYAML API 插件(环境相关,具体问题具体分析)
3)如果插件升级失败,导致 Jenkins 显示 Error 页面,我们通过 rsync 重置 plugins 目录,然后再次尝试插件升级;

with Docker Compose | Jenkins 2.340-jdk8

如下配置,仅供参考:

version: '3'
services:
  jenkins-master:
    image: 'jenkins/jenkins:2.340-jdk8'
    container_name: jenkins-master
    environment:
      - JAVA_OPTS="-Duser.timezone=Asia/Shanghai -Dhudson.model.DirectoryBrowserSupport.CSP=''"
    volumes:
      - /etc/localtime:/etc/localtime
      - ./data:/var/jenkins_home
    ports:
      - 8088:8080
      - 50000:50000
    restart: always

注意,如果是迁移到 data 目录,则需要修改权限:chown 1000:1000 ./data -R

通过查看启动日志,获得默认密码,/var/jenkins_home/secrets/initialAdminPassword

Nginx Reverse Proxy

server {

    listen 80 default;
    server_name ci.devops.example.com;

    location / {

        proxy_pass http://127.0.0.1:8080;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        client_max_body_size 10m;
    }
}

在反向代理后,出现 HTTP Basic authentication 重复认证

Wikipedia/Basic access authentication
How to define the basic HTTP authentication using cURL correctly?

问题描述:
为了提高安全性,使用 Nginx 反向代理 Jenkins 后,又在 Nginx 中配置了 HTTP Basic Authentication 功能,但是出现了“认证窗口不停弹出”的问题;
关于 HTTP Basic Authentication 的配置参考 Restricting Access with HTTP Basic Authentication 一文;

问题原因:
使用 curl 命令请求(curl --user user:password http://),返回 401 认证失败页面,该页面是 Jenkins 返回的(页面上由 Jetty…… 等内容);
修改 Jenkins 调试等级并打开访问日志,请求日志中出现了 401 认证失败的请求;
前端 Nginx 将 Authorization 请求头传给 Jenkins 服务,但是 Jenkins 并没有配置认证,而导致认证失败;
但实际上,我们并不需要把 Authorization 头传递给 Jenkins 服务;

解决办法:
修改 Nginx 配置文件,在转发时移除 Authorization 头:proxy_set_header Authorization “”;
通过置空来移除头部,参考官方文档说明:「Module ngx_http_proxy_module/proxy_set_header

with Docker Compose | Jenkins 2.373

2.373 ⇒ 2.375 ⇒ 2.387 ⇒ 2.401 ⇒ 2.414 ⇒ 2.426

参考 Jenkins LTS Upgrade Guide 文档,获取版本间的变化日志;

根据我们部署及配置,升级过程较为简单:

docker pull jenkins/jenkins:2.xxx
vim docker-compose.yaml
docker-compose up -d

with Docker Compose | Jenkins 2.426

Run 2.426 with Docker Compose

停止 Jenkins 服务,复制 /var/lib/jenkins/ 目录

通过 docker-compose.yaml 运行:

version: '3'
services:
  jenkins-master:
    image: docker.io/jenkins/jenkins:2.469
    container_name: jenkins-master
    environment:
      - JENKINS_JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
    volumes:
      - /etc/localtime:/etc/localtime
      - ./data:/var/jenkins_home
    ports:
      - 60080:8080
      - 50000:50000
    restart: always

2.426 ⇒ 2.458

参考 Jenkins LTS Upgrade Guide 文档,获取版本间的变化日志;

根据我们部署及配置,升级过程较为简单:

docker pull jenkins/jenkins:2.xxx
vim docker-compose.yaml
docker-compose up -d

2.469 ⇒ 2.477

根据 Changelog/2.475 文档,需要升级 LDAP 插件:

Users of the LDAP plugin must upgrade it to version 733.vd3700c27b_043 in lockstep with upgrading Jenkins core.

下载插件,手动安装

停止服务。

然后,再升级到 2.477 版本。

2.477 ⇒ 2.487

1)数据备份
2)直接升级进行即可

废弃 | 在 Tomcat 中,运行 Jenkins 服务

Jenkins/Installing Jenkins
How to Install Jenkins on the Apache Tomcat Server
How to set Jenkins_Home hosted on apache tomcat

该笔记将记录:在 Tomcat 中,运行 Jenkins 服务,而不是运行独立的 Jenkins 服务;

注意,在实际的生产中,我们并未在 Tomcat 中部署 Jenkins 服务,该笔记属于实验性质。

第一步、安装 Tomcat 服务

我们直接从发行办的仓库中安装:

# 安装服务(Kali)
apt-get install tomcat9

# 启动服务,并开机启动
systemctl enable tomcat9

发行版不同,安装方法不同,细节不再赘述;

第二步、安装 Jenkins 服务

wget -P /var/lib/tomcat9/webapps/ http://mirrors.jenkins.io/war-stable/latest/jenkins.war

然后最自动生成 jenkins 目录;

第三步、修改配置文件

为什么需要进行该步骤?
1)进行该步骤配置是因为发行版自带的 Tomcat 进行安全配置,执行命令 systemctl cat tomcat9.service 了解配置;
2)阅读 systemd.exec(5) 手册,了解 PrivateTmp= ReadWritePaths= 参数;

修改 /etc/tomcat9/context.xml 配置,设置 JENKINS_HOME 变量:

<Context>
	...
	<Environment name="JENKINS_HOME" value="/var/lib/jenkins/" type="java.lang.String"/>
	...
</Context>

创建 JENKINS_HOME 目录

mkdir -pv /var/lib/jenkins/
chown -R tomcat: /var/lib/jenkins/

调整 tomcat9.service 配置

# systemctl edit tomcat9.service
[Service]
ReadWritePaths=/var/lib/jenkins/

第四步、启动 Tomcat 服务

systemcat start tomcat9

最后启动浏览器访问,http://<ip address>/jenkins/,按照提示进行初始化即可;