目录
一、前言
二、CI/CD的定义与核心原则
CI/CD在现代软件开发中的重要性
CI/CD与Jenkins的关系
三、Jenkins部署方式汇总
1. 独立服务器部署
(1)离线安装
(2)在线安装
2. Docker容器部署
3. Kubernetes集群部署
4. 云服务部署
5. 分布式部署
四、总结
一、前言
在当今快节奏的软件开发世界中,持续集成(Continuous Integration, CI)与持续交付(Continuous Delivery, CD)已成为确保软件质量和加速交付周期的关键实践。CI/CD不仅仅是一种技术实现,更是一种文化转变,它要求开发团队不断迭代、持续测试,并自动化整个软件交付流程。本文将深入探讨CI/CD的定义、核心原则,并对当前广泛应用于CI/CD的部署工具Jenkins及其常见的部署方式进行总结。
二、CI/CD的定义与核心原则
持续集成(CI) 是一种开发实践,要求开发人员频繁地将代码集成到共享仓库中。每次集成都通过自动化构建和测试来验证,从而尽早发现问题。CI的核心原则包括:频繁提交、自动化构建、自动化测试、快速反馈和修复问题。
持续交付(CD) 是CI的延伸,它确保代码变更可以自动、可靠地部署到生产环境。CD的核心原则包括:自动化部署、环境一致性、可重复的部署过程和快速回滚能力。
另外还有一种呢,就是持续部署(Continuous Deployment),它在持续交付的基础上,把部署到生产环境的过程自动化,持续部署和持续交付的区别就是最终部署到生产环境是自动化的。
CI/CD在现代软件开发中的重要性
在当今竞争激烈的市场环境中,软件开发团队面临着快速交付高质量软件的压力。CI/CD通过以下几个方面显著提升了软件开发的效率和质量:
-
加速交付周期:通过自动化构建和部署过程,CI/CD大大减少了手动操作的时间和错误,使得团队能够更快地将新功能和修复交付给用户。
-
提高软件质量:频繁的自动化测试确保了代码的稳定性和可靠性,减少了缺陷在后期发现的风险,从而提高了软件的整体质量。
-
增强团队协作:CI/CD鼓励团队成员频繁集成代码,这促进了代码共享和知识交流,增强了团队的协作能力。
-
提高部署可靠性:通过自动化部署和环境一致性,CI/CD减少了人为错误,确保了部署过程的可靠性和可重复性。
-
快速反馈和适应变化:CI/CD提供了快速反馈机制,使得团队能够迅速响应问题和市场变化,增强了组织的适应性和竞争力。
CI/CD与Jenkins的关系
Jenkins是一个开源的自动化服务器,广泛用于实现CI/CD流水线。它通过插件生态系统支持各种构建、测试和部署工具,使得开发团队可以轻松地集成和自动化整个软件交付流程。Jenkins不仅简化了CI/CD的实施,还提供了丰富的监控和报告功能,帮助团队更好地理解和管理其交付过程。
三、Jenkins部署方式汇总
Jenkins的支持部署方式多种多样,可以根据不同的需求和环境选择最合适的方法。以下是对Jenkins几种常见部署方式的简单说明及流程说明:
1. 独立服务器部署
这是最常见的Jenkins部署方式。在这种模式下,Jenkins作为一个独立的Java应用程序运行在一台或多台服务器上。用户可以通过浏览器访问Jenkins的Web界面来管理和执行构建任务。
优点:
-
简单易行,无需复杂的配置。
-
适用于中小型项目和团队。
缺点:
-
扩展性和高可用性有限。
-
需要手动管理和维护服务器。
这里笔者通过离线和在线两种安装方式和流程进行说明:
(1)离线安装
由于Jenkins是基于Java开发的一种持续集成工具,因此在离线安装前必须安装相对应的java环境。为了确保与Jenkins的兼容性,我们在安装JDK前确认其版本需求。Jenkins的各版本对Java运行环境(JRE)的具体版本有不同的要求。可以直接访问Jenkins的官方包仓库页面来获取最准确的信息。
这里笔者选择安装最新的2.463,因此至少需要一个Java17的环境。但是Ubuntu系统上还是8,所以得重新下载换一下Java环境:
root@master01:/etc/docker# java -version
openjdk version "1.8.0_422"
OpenJDK Runtime Environment (build 1.8.0_422-8u422-b05-1~22.04-b05)
OpenJDK 64-Bit Server VM (build 25.422-b05, mixed mode)
首先根据JDK下载地址,现在jdk17的适用系统的离线包,这里笔者用的是ubuntu对应的deb,也可以使用tar.gz的也行:
然后进行jdk17的安装:
root@master01:/opt# mkdir jdk17
root@master01:/opt# cd jdk17
#下载安装包
root@master01:/opt/jdk17# wget https://builds.openlogic.com/downloadJDK/openlogic-openjdk/17.0.12+7/openlogic-openjdk-17.0.12+7-linux-x64-deb.deb
#安装dpkg和gdebi工具
root@master01:/opt/jdk17# apt install dpkg gdebi
#开始安装
root@master01:/opt/jdk17# gdebi openlogic-openjdk-17.0.12+7-linux-x64-deb.deb
#除了系统默认安装的8以外,17已经安装在/usr/lib/jvm/目录下了
root@master01:/opt/jdk17# ls -l /usr/lib/jvm/
总计 8
lrwxrwxrwx 1 root root 20 2月 27 15:25 java-1.8.0-openjdk-amd64 -> java-8-openjdk-amd64
drwxr-xr-x 5 root root 4096 4月 1 21:08 java-8-openjdk-amd64
drwxr-xr-x 11 root root 4096 8月 23 16:18 openlogic-openjdk-17-hotspot-amd64
#配置环境变量
root@master01:/opt/jdk17# export JAVA_HOME=/usr/lib/jvm/openlogic-openjdk-17-hotspot-amd64/
root@master01:/opt/jdk17# export PATH=$JAVA_HOME/bin:$PATH
#检查配置信息
root@master01:/opt/jdk17# echo $JAVA_HOME
/usr/lib/jvm/openlogic-openjdk-17-hotspot-amd64/
root@master01:/opt/jdk17# java -version
openjdk version "17.0.12" 2024-07-16
OpenJDK Runtime Environment OpenLogic-OpenJDK (build 17.0.12+7-adhoc.root.jdk17u)
OpenJDK 64-Bit Server VM OpenLogic-OpenJDK (build 17.0.12+7-adhoc.root.jdk17u, mixed mode, sharing)
#保存文件并使更改生效
root@master01:/opt/jdk17# source /etc/profile
接着下载Jenkins的离线安装包进行安装操作。安装前建议保留8080端口,因为jenkins服务默认运行端口是8080,尽量避免发生端口占用情况,或者修改服务端口信息。安装包推荐在Jenkins的阿里云镜像站进行下载,会比较快。
root@master01:/opt/jdk17# wget https://mirrors.aliyun.com/jenkins/debian/jenkins_2.463_all.deb
root@master01:/opt/jdk17# wget https://mirrors.aliyun.com/jenkins/debian/jenkins_2.463_all.deb
--2024-08-23 16:33:58-- https://mirrors.aliyun.com/jenkins/debian/jenkins_2.463_all.deb
正在解析主机 mirrors.aliyun.com (mirrors.aliyun.com)... 45.253.17.230, 45.253.17.236, 45.253.17.234, ...
正在连接 mirrors.aliyun.com (mirrors.aliyun.com)|45.253.17.230|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度: 91211108 (87M) [application/vnd.debian.binary-package]
正在保存至: ‘jenkins_2.463_all.deb’
jenkins_2.463_all.deb 100%[=========================================================================================>] 86.99M 285KB/s 用时 4m 48s
2024-08-23 16:38:46 (310 KB/s) - 已保存 ‘jenkins_2.463_all.deb’ [91211108/91211108])
root@master01:/opt/jdk17# ll
总计 312852
drwxr-xr-x 2 root root 4096 8月 23 16:33 ./
drwxr-xr-x 9 root root 4096 8月 23 15:58 ../
-rw-r--r-- 1 root root 91211108 6月 18 21:33 jenkins_2.463_all.deb
-rw-r--r-- 1 root root 229128664 7月 24 20:59 openlogic-openjdk-17.0.12+7-linux-x64-deb.deb
root@master01:/opt/jdk17# gdebi jenkins_2.463_all.deb
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Reading state information... Done
Jenkins is the leading open source automation server supported by a large and growing community of developers, testers, designers and other people interested in continuous integration, continuous delivery and modern software delivery practices. Built on the Java Virtual Machine (JVM), it provides more than 1,800 plugins that extend Jenkins to automate with practically any technology software delivery teams use. In 2022, Jenkins reached 300,000 known installations making it the most widely deployed automation server.
.
For more information, see https://www.jenkins.io.
您是否想安装这个软件包?[y/N]:y
/usr/bin/gdebi:113: FutureWarning: Possible nested set at position 1
c = findall("[[(](\S+)/\S+[])]", msg)[0].lower()
正在选中未选择的软件包 jenkins。
(正在读取数据库 ... 系统当前共安装有 229443 个文件和目录。)
准备解压 jenkins_2.463_all.deb ...
正在解压 jenkins (2.463) ...
正在设置 jenkins (2.463) ...
Created symlink /etc/systemd/system/multi-user.target.wants/jenkins.service → /lib/systemd/system/jenkins.service.
Could not execute systemctl: at /usr/bin/deb-systemd-invoke line 142.
但是启动报错了,查看一下日志:
root@master01:/opt/jdk17# journalctl -xu jenkins.service
8月 23 16:39:32 master01 jenkins[145183]: Error: A JNI error has occurred, please check your installation and try again
8月 23 16:39:32 master01 jenkins[145183]: Exception in thread "main" java.lang.UnsupportedClassVersionError: executable/Main has been compiled by a more recent version of th>
8月 23 16:39:32 master01 jenkins[145183]: at java.lang.ClassLoader.defineClass1(Native Method)
8月 23 16:39:32 master01 jenkins[145183]: at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
8月 23 16:39:32 master01 jenkins[145183]: at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
8月 23 16:39:32 master01 jenkins[145183]: at java.net.URLClassLoader.defineClass(URLClassLoader.java:473)
8月 23 16:39:32 master01 jenkins[145183]: at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
8月 23 16:39:32 master01 jenkins[145183]: at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
8月 23 16:39:32 master01 jenkins[145183]: at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
8月 23 16:39:32 master01 jenkins[145183]: at java.security.AccessController.doPrivileged(Native Method)
8月 23 16:39:32 master01 jenkins[145183]: at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
8月 23 16:39:32 master01 jenkins[145183]: at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
8月 23 16:39:32 master01 jenkins[145183]: at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
8月 23 16:39:32 master01 jenkins[145183]: at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
8月 23 16:39:32 master01 jenkins[145183]: at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:621)
8月 23 16:39:32 master01 systemd[1]: jenkins.service: Main process exited, code=exited, status=1/FAILURE
分析原因,可能是ubuntu系统当初本来存在一个jdk8,现在又下载了一个17导致的,虽然查看java和javac版本都是17,但是可能存在收到jdk8的影响。于是决定删除原有的jdk8:
root@master01:/opt/jdk17# apt-get purge openjdk*
(正在读取数据库 ... 系统当前共安装有 229243 个文件和目录。)
正在清除 openjdk-8-jre-headless:amd64 (8u422-b05-1~22.04) 的配置文件 ...
root@master01:/opt/jdk17# ls -l /usr/lib/jvm/
总计 4
drwxr-xr-x 11 root root 4096 8月 23 16:18 openlogic-openjdk-17-hotspot-amd64
清除完成后就只剩jdk17的环境了,然后重启jenkins试试:
root@master01:/opt/jdk17# systemctl restart jenkins
root@master01:/opt/jdk17# systemctl status jenkins
● jenkins.service - Jenkins Continuous Integration Server
Loaded: loaded (/lib/systemd/system/jenkins.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2024-08-23 17:06:38 CST; 7s ago
Main PID: 155981 (java)
Tasks: 54 (limit: 4546)
Memory: 645.4M
CPU: 16.199s
CGroup: /system.slice/jenkins.service
└─155981 /usr/bin/java -Djava.awt.headless=true -jar /usr/share/java/jenkins.war --webroot=/var/cache/jenkins/war --httpPort=8080
8月 23 17:06:15 master01 jenkins[155981]: 4468ad878e2a48f9ac298b3b82920863
8月 23 17:06:15 master01 jenkins[155981]: This may also be found at: /var/lib/jenkins/secrets/initialAdminPassword
8月 23 17:06:15 master01 jenkins[155981]: *************************************************************
8月 23 17:06:15 master01 jenkins[155981]: *************************************************************
8月 23 17:06:15 master01 jenkins[155981]: *************************************************************
8月 23 17:06:25 master01 jenkins[155981]: 2024-08-23 09:06:25.392+0000 [id=54] INFO h.m.DownloadService$Downloadable#load: Obtained the updated data file for h>
8月 23 17:06:25 master01 jenkins[155981]: 2024-08-23 09:06:25.393+0000 [id=54] INFO hudson.util.Retrier#start: Performed the action check updates server succes>
8月 23 17:06:38 master01 jenkins[155981]: 2024-08-23 09:06:38.575+0000 [id=34] INFO jenkins.InitReactorRunner$1#onAttained: Completed initialization
8月 23 17:06:38 master01 jenkins[155981]: 2024-08-23 09:06:38.587+0000 [id=25] INFO hudson.lifecycle.Lifecycle#onReady: Jenkins is fully up and running
8月 23 17:06:38 master01 systemd[1]: Started Jenkins Continuous Integration Server.
搞定,并且默认端口8080可实现访问:
(2)在线安装
这类安装方式就比较方便了,只要网络状态良好,便可快速搭建一个Jenkins。
要在Ubuntu上使用Jenkins的存储库,首先将密钥添加到系统中(用于每周发布行),这是Jenkins的Debian软件包库,用于自动安装和升级:
root@master01:/opt/jenkins# wget -O /usr/share/keyrings/jenkins-keyring.asc \
https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
--2024-08-23 17:27:49-- https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
正在解析主机 pkg.jenkins.io (pkg.jenkins.io)... 146.75.114.133, 2a04:4e42:8c::645
正在连接 pkg.jenkins.io (pkg.jenkins.io)|146.75.114.133|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度: 3175 (3.1K) [application/pgp-keys]
正在保存至: ‘/usr/share/keyrings/jenkins-keyring.asc’
/usr/share/keyrings 100%[===================>] 3.10K --.-KB/s 用时 0s
2024-08-23 17:27:49 (56.7 MB/s) - 已保存 ‘/usr/share/keyrings/jenkins-keyring.asc’ [3175/3175])
然后添加一个Jenkins apt存储库条目:
root@master01:/opt/jenkins# echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]" \
https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
/etc/apt/sources.list.d/jenkins.list > /dev/null
最后更新一下本地包,在线安装jdk与jenkins:
root@master01:/opt/jenkins# apt-get update
root@master01:/opt/jenkins# apt-get install fontconfig openjdk-17-jre
正在读取软件包列表... 完成
正在分析软件包的依赖关系树... 完成
正在读取状态信息... 完成
fontconfig 已经是最新版 (2.13.1-4.2ubuntu5)。
fontconfig 已设置为手动安装。
下列软件包是自动安装的并且现在不需要了:
libwpe-1.0-1 libwpebackend-fdo-1.0-1
使用'apt autoremove'来卸载它(它们)。
将会同时安装下列软件:
fonts-dejavu-extra libatk-wrapper-java libatk-wrapper-java-jni
openjdk-17-jre-headless
建议安装:
fonts-ipafont-gothic fonts-ipafont-mincho fonts-wqy-microhei
| fonts-wqy-zenhei
下列【新】软件包将被安装:
fonts-dejavu-extra libatk-wrapper-java libatk-wrapper-java-jni
openjdk-17-jre openjdk-17-jre-headless
升级了 0 个软件包,新安装了 5 个软件包,要卸载 0 个软件包,有 107 个软件包未被升级。
需要下载 50.6 MB 的归档。
解压缩后会消耗 201 MB 的额外空间。
您希望继续执行吗? [Y/n] y
……
root@master01:/opt/jenkins# apt-get install jenkins
正在读取软件包列表... 完成
正在分析软件包的依赖关系树... 完成
正在读取状态信息... 完成
下列软件包是自动安装的并且现在不需要了:
libwpe-1.0-1 libwpebackend-fdo-1.0-1
使用'apt autoremove'来卸载它(它们)。
下列【新】软件包将被安装:
jenkins
升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 107 个软件包未被升级。
需要下载 91.2 MB 的归档。
解压缩后会消耗 93.4 MB 的额外空间。
获取:1 https://pkg.jenkins.io/debian-stable binary/ jenkins 2.462.1 [91.2 MB]
已下载 91.2 MB,耗时 2分 40秒 (569 kB/s)
正在选中未选择的软件包 jenkins。
(正在读取数据库 ... 系统当前共安装有 218587 个文件和目录。)
准备解压 .../jenkins_2.462.1_all.deb ...
正在解压 jenkins (2.462.1) ...
正在设置 jenkins (2.462.1) ...
Created symlink /etc/systemd/system/multi-user.target.wants/jenkins.service → /lib/systemd/system/jenkins.service.
root@master01:/opt/jenkins# whereis jenkins
jenkins: /usr/bin/jenkins /usr/share/jenkins
root@master01:/opt/jenkins# cat /etc/systemd/system/multi-user.target.wants/jenkins.service
#
# This file is managed by systemd(1). Do NOT edit this file manually!
# To override these settings, run:
#
# systemctl edit jenkins
#
# For more information about drop-in files, see:
#
# https://www.freedesktop.org/software/systemd/man/systemd.unit.html
#
[Unit]
Description=Jenkins Continuous Integration Server
Requires=network.target
After=network.target
[Service]
Type=notify
NotifyAccess=main
ExecStart=/usr/bin/jenkins
Restart=on-failure
SuccessExitStatus=143
# Configures the time to wait for start-up. If Jenkins does not signal start-up
# completion within the configured time, the service will be considered failed
# and will be shut down again. Takes a unit-less value in seconds, or a time span
# value such as "5min 20s". Pass "infinity" to disable the timeout logic.
#TimeoutStartSec=90
# Unix account that runs the Jenkins daemon
# Be careful when you change this, as you need to update the permissions of
# $JENKINS_HOME, $JENKINS_LOG, and (if you have already run Jenkins)
# $JENKINS_WEBROOT.
User=jenkins
Group=jenkins
# Directory where Jenkins stores its configuration and workspaces
Environment="JENKINS_HOME=/var/lib/jenkins"
WorkingDirectory=/var/lib/jenkins
# Location of the Jenkins WAR
#Environment="JENKINS_WAR=/usr/share/java/jenkins.war"
# Location of the exploded WAR
Environment="JENKINS_WEBROOT=%C/jenkins/war"
# Location of the Jenkins log. By default, systemd-journald(8) is used.
#Environment="JENKINS_LOG=%L/jenkins/jenkins.log"
# The Java home directory. When left empty, JENKINS_JAVA_CMD and PATH are consulted.
#Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"
# The Java executable. When left empty, JAVA_HOME and PATH are consulted.
#Environment="JENKINS_JAVA_CMD=/etc/alternatives/java"
# Arguments for the Jenkins JVM
Environment="JAVA_OPTS=-Djava.awt.headless=true"
# Unix Domain Socket to listen on for local HTTP requests. Default is disabled.
#Environment="JENKINS_UNIX_DOMAIN_PATH=/run/jenkins/jenkins.socket"
# IP address to listen on for HTTP requests.
# The default is to listen on all interfaces (0.0.0.0).
#Environment="JENKINS_LISTEN_ADDRESS="
# Port to listen on for HTTP requests. Set to -1 to disable.
# To be able to listen on privileged ports (port numbers less than 1024),
# add the CAP_NET_BIND_SERVICE capability to the AmbientCapabilities
# directive below.
Environment="JENKINS_PORT=8080"
# IP address to listen on for HTTPS requests. Default is disabled.
#Environment="JENKINS_HTTPS_LISTEN_ADDRESS="
# Port to listen on for HTTPS requests. Default is disabled.
# To be able to listen on privileged ports (port numbers less than 1024),
# add the CAP_NET_BIND_SERVICE capability to the AmbientCapabilities
# directive below.
#Environment="JENKINS_HTTPS_PORT=443"
# Path to the keystore in JKS format (as created by the JDK's keytool).
# Default is disabled.
#Environment="JENKINS_HTTPS_KEYSTORE=/path/to/keystore.jks"
# Password to access the keystore defined in JENKINS_HTTPS_KEYSTORE.
# Default is disabled.
#Environment="JENKINS_HTTPS_KEYSTORE_PASSWORD=s3cR3tPa55w0rD"
# IP address to listen on for HTTP2 requests. Default is disabled.
#Environment="JENKINS_HTTP2_LISTEN_ADDRESS="
# HTTP2 port to listen on. Default is disabled.
# To be able to listen on privileged ports (port numbers less than 1024),
# add the CAP_NET_BIND_SERVICE capability to the AmbientCapabilities
# directive below.
#Environment="JENKINS_HTTP2_PORT="
# Controls which capabilities to include in the ambient capability set for the
# executed process. Takes a whitespace-separated list of capability names, e.g.
# CAP_SYS_ADMIN, CAP_DAC_OVERRIDE, CAP_SYS_PTRACE. Ambient capability sets are
# useful if you want to execute a process as a non-privileged user but still
# want to give it some capabilities. For example, add the CAP_NET_BIND_SERVICE
# capability to be able to listen on privileged ports (port numbers less than
# 1024).
#AmbientCapabilities=CAP_NET_BIND_SERVICE
# Debug level for logs. The higher the value, the more verbose. 5 is INFO.
#Environment="JENKINS_DEBUG_LEVEL=5"
# Set to true to enable logging to /var/log/jenkins/access_log.
#Environment="JENKINS_ENABLE_ACCESS_LOG=false"
# Servlet context (important if you want to use reverse proxying)
#Environment="JENKINS_PREFIX=/jenkins"
# Arbitrary additional arguments to pass to Jenkins.
# Full option list: java -jar jenkins.war --help
#Environment="JENKINS_OPTS="
# Maximum core file size. If unset, the value from the OS is inherited.
#LimitCORE=infinity
# Maximum file size. If unset, the value from the OS is inherited.
#LimitFSIZE=infinity
# File descriptor limit. If unset, the value from the OS is inherited.
#LimitNOFILE=8192
# Maximum number of processes. If unset, the value from the OS is inherited.
#LimitNPROC=32768
# Set the umask to control the permission bits of files that Jenkins creates.
#
# 0027 makes files read-only for group and inaccessible for others, which some
# security sensitive users might consider beneficial, especially if Jenkins
# is running on a server that is used for multiple purposes. Beware that 0027
# permissions would interfere with sudo scripts that run on the controller
# (see JENKINS-25065).
#
# Note also that the particularly sensitive parts of $JENKINS_HOME (such as
# credentials) are always written without 'other' access. So the umask values
# only affect job configuration, build records, etc.
#
# If unset, the value from the OS is inherited, which is normally 0022.
# The default umask comes from pam_umask(8) and /etc/login.defs.
#UMask=0022
[Install]
WantedBy=multi-user.target
有端口问题就调整一下Environment="JENKINS_PORT=8080"
即可。运行没有问题后即可看到访问正常:
2. Docker容器部署
通过Docker容器部署Jenkins可以实现快速启动和环境隔离。用户可以使用官方的Jenkins Docker镜像,通过Docker命令或Docker Compose来启动Jenkins容器。
优点:
-
环境一致性,便于在不同环境中迁移。
-
快速部署和扩展。
-
便于集成其他Docker化的服务和工具。
缺点:
-
需要一定的Docker知识。
-
对于复杂的环境可能需要额外的配置和管理。
但是实际上,虽然官方推荐使用Docker Hub存储库中的jenkins/jenkins镜像,此映像包含Jenkins的当前长期支持(LTS)版本,即:jenkins/jenkins:lts,该版本已准备好用于生产。但是,这个镜像不包含Docker CLI,也没有与常用的blueocean插件及其功能捆绑在一起。所以要使用Jenkins和Docker的全部功能,一般建议使用Docker映像是jenkinsci/blueocean
image(来自 the Docker Hub repository)。 该镜像包含当前的长期支持 (LTS) 的Jenkins版本 (可以投入使用) ,捆绑了所有Blue Ocean插件和功能。这意味着我们不需要单独安装Blue Ocean插件。
root@master01:/opt# mkdir jenkins
root@master01:/opt# cd jenkins/
root@master01:/opt/jenkins# docker run -d -p 8084:8080 -p 50000:50000 --restart=unless-stopped -v /opt/jenkins/data:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock --name jenkins jenkinsci/blueocean
#这里由于官方源被强了,所以用国内源进行拉取
root@master01:/opt/jenkins# docker run -d -p 8084:8080 -p 50000:50000 --restart=unless-stopped -v /opt/jenkins/data:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock --name jenkins swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkinsci/blueocean:1.25.7
Unable to find image 'swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkinsci/blueocean:1.25.7' locally
1.25.7: Pulling from ddn-k8s/docker.io/jenkinsci/blueocean
213ec9aee27d: Pull complete
9fb6b045bfc8: Pull complete
1a7d7223e42d: Pull complete
8f2b061b68da: Pull complete
bba48a821480: Pull complete
0061c72f26bd: Pull complete
f65ed3fbea93: Pull complete
3509f53c6b7b: Pull complete
28ea9c56d127: Pull complete
b3b3ea5ca7f4: Pull complete
e5ecc395b9e7: Pull complete
a4cea1bad4ff: Pull complete
d2d0e6e9298c: Pull complete
f786c314ed83: Pull complete
Digest: sha256:f27933313986f7fb0b5784aa6520ebddc455ce258cbf4d13a3e3cf9d4c94d992
Status: Downloaded newer image for swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkinsci/blueocean:1.25.7
1f11258192d716db37d55f84d62ab2321ce4c49805079d4edabf85f97a4f1a01
root@master01:/opt/jenkins# docker ps -f name=jenkins
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f11258192d7 swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkinsci/blueocean:1.25.7 "/sbin/tini -- /usr/…" About a minute ago Restarting (1) 11 seconds ago jenkins
但是出现点小插曲,启动失败了,查看日志:
root@master01:/opt/jenkins# docker logs -f --tail 200 jenkins
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
可以看到是权限不够的原因,所以给足一下jenkins下挂载的data目录权限,再重启试试:
root@master01:/opt/jenkins# chmod 777 -R data/
root@master01:/opt/jenkins# docker restart jenkins
jenkins
root@master01:/opt/jenkins# docker logs -f --tail 200 jenkins
Running from: /usr/share/jenkins/jenkins.war
webroot: EnvVars.masterEnvVars.get("JENKINS_HOME")
2024-08-23 14:29:27.311+0000 [id=1] INFO org.eclipse.jetty.util.log.Log#initialized: Logging initialized @486ms to org.eclipse.jetty.util.log.JavaUtilLog
2024-08-23 14:29:27.411+0000 [id=1] INFO winstone.Logger#logInternal: Beginning extraction from war file
2024-08-23 14:29:28.328+0000 [id=1] WARNING o.e.j.s.handler.ContextHandler#setContextPath: Empty contextPath
2024-08-23 14:29:28.409+0000 [id=1] INFO org.eclipse.jetty.server.Server#doStart: jetty-9.4.45.v20220203; built: 2022-02-03T09:14:34.105Z; git: 4a0c91c0be53805e3fcffdcdcc9587d5301863db; jvm 11.0.16.1+1
2024-08-23 14:29:28.688+0000 [id=1] INFO o.e.j.w.StandardDescriptorProcessor#visitServlet: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2024-08-23 14:29:28.735+0000 [id=1] INFO o.e.j.s.s.DefaultSessionIdManager#doStart: DefaultSessionIdManager workerName=node0
2024-08-23 14:29:28.735+0000 [id=1] INFO o.e.j.s.s.DefaultSessionIdManager#doStart: No SessionScavenger set, using defaults
2024-08-23 14:29:28.737+0000 [id=1] INFO o.e.j.server.session.HouseKeeper#startScavenging: node0 Scavenging every 660000ms
2024-08-23 14:29:29.301+0000 [id=1] INFO hudson.WebAppMain#contextInitialized: Jenkins home directory: /var/jenkins_home found at: EnvVars.masterEnvVars.get("JENKINS_HOME")
2024-08-23 14:29:29.652+0000 [id=1] INFO o.e.j.s.handler.ContextHandler#doStart: Started w.@73a19967{Jenkins v2.346.3,/,file:///var/jenkins_home/war/,AVAILABLE}{/var/jenkins_home/war}
2024-08-23 14:29:29.686+0000 [id=1] INFO o.e.j.server.AbstractConnector#doStart: Started ServerConnector@39a8312f{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
2024-08-23 14:29:29.686+0000 [id=1] INFO org.eclipse.jetty.server.Server#doStart: Started @2864ms
2024-08-23 14:29:29.687+0000 [id=24] INFO winstone.Logger#logInternal: Winstone Servlet Engine running: controlPort=disabled
2024-08-23 14:29:29.976+0000 [id=31] INFO jenkins.InitReactorRunner$1#onAttained: Started initialization
2024-08-23 14:29:30.162+0000 [id=33] INFO hudson.PluginManager#considerDetachedPlugin: Loading a detached plugin as a dependency: /var/jenkins_home/plugins/javax-mail-api.jpi
2024-08-23 14:29:30.283+0000 [id=36] INFO hudson.PluginManager#considerDetachedPlugin: Loading a detached plugin as a dependency: /var/jenkins_home/plugins/sshd.jpi
2024-08-23 14:29:32.466+0000 [id=34] INFO hudson.PluginManager#considerDetachedPlugin: Loading a detached plugin as a dependency: /var/jenkins_home/plugins/bouncycastle-api.jpi
2024-08-23 14:29:32.548+0000 [id=34] INFO hudson.PluginManager#considerDetachedPlugin: Loading a detached plugin as a dependency: /var/jenkins_home/plugins/command-launcher.jpi
2024-08-23 14:29:32.561+0000 [id=34] INFO hudson.PluginManager#considerDetachedPlugin: Loading a detached plugin as a dependency: /var/jenkins_home/plugins/jdk-tool.jpi
2024-08-23 14:29:32.836+0000 [id=29] INFO jenkins.InitReactorRunner$1#onAttained: Listed all plugins
2024-08-23 14:29:37.513+0000 [id=30] INFO jenkins.InitReactorRunner$1#onAttained: Prepared all plugins
2024-08-23 14:29:37.556+0000 [id=33] INFO jenkins.InitReactorRunner$1#onAttained: Started all plugins
2024-08-23 14:29:37.562+0000 [id=33] INFO jenkins.InitReactorRunner$1#onAttained: Augmented all extensions
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.codehaus.groovy.vmplugin.v7.Java7$1 (file:/var/jenkins_home/war/WEB-INF/lib/groovy-all-2.4.21.jar) to constructor java.lang.invoke.MethodHandles$Lookup(java.lang.Class,int)
WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.vmplugin.v7.Java7$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
2024-08-23 14:29:39.289+0000 [id=33] INFO jenkins.InitReactorRunner$1#onAttained: System config loaded
2024-08-23 14:29:39.290+0000 [id=33] INFO jenkins.InitReactorRunner$1#onAttained: System config adapted
2024-08-23 14:29:39.291+0000 [id=34] INFO jenkins.InitReactorRunner$1#onAttained: Loaded all jobs
2024-08-23 14:29:39.309+0000 [id=31] INFO jenkins.InitReactorRunner$1#onAttained: Configuration for all jobs updated
2024-08-23 14:29:39.333+0000 [id=50] INFO hudson.model.AsyncPeriodicWork#lambda$doRun$1: Started Download metadata
2024-08-23 14:29:39.344+0000 [id=50] INFO hudson.util.Retrier#start: Attempt #1 to do the action check updates server
2024-08-23 14:29:39.840+0000 [id=33] INFO jenkins.install.SetupWizard#init:
*************************************************************
*************************************************************
*************************************************************
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
2d49484371bc4af28066413e0465f0b5
This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
*************************************************************
*************************************************************
*************************************************************
2024-08-23 14:30:07.512+0000 [id=33] INFO jenkins.InitReactorRunner$1#onAttained: Completed initialization
2024-08-23 14:30:07.547+0000 [id=23] INFO hudson.lifecycle.Lifecycle#onReady: Jenkins is fully up and running
2024-08-23 14:30:08.605+0000 [id=50] INFO h.m.DownloadService$Downloadable#load: Obtained the updated data file for hudson.tasks.Maven.MavenInstaller
2024-08-23 14:30:10.715+0000 [id=50] INFO h.m.DownloadService$Downloadable#load: Obtained the updated data file for hudson.tools.JDKInstaller
2024-08-23 14:30:10.716+0000 [id=50] INFO hudson.util.Retrier#start: Performed the action check updates server successfully at the attempt #1
2024-08-23 14:30:10.721+0000 [id=50] INFO hudson.model.AsyncPeriodicWork#lambda$doRun$1: Finished Download metadata. 31,387 ms
搞定,可访问端口8084并且可以看到这里还显示了解锁jenkins的密码:2d49484371bc4af28066413e0465f0b5
,在访问页面输入一下就能进入jenkins新手入门界面了。
3. Kubernetes集群部署
Kubernetes (k8)是一个用于自动化部署、扩展和管理容器化应用程序的开源系统。Kubernetes集群为Jenkins添加了一个新的自动化层。Kubernetes确保资源得到有效利用,并且服务器和底层基础设施不会过载。Kubernetes编排容器部署的能力确保了Jenkins始终拥有适当数量的可用资源。
在Kubernetes集群上托管Jenkins对于基于Kubernetes的部署和基于动态容器的可扩展Jenkins代理是有益的。
优点:
-
高可用性和弹性扩展。
-
与Kubernetes生态系统无缝集成。
-
自动化管理和扩展。
缺点:
-
配置和管理相对复杂。
-
需要Kubernetes和Helm知识。
对k8s搭建不太熟的小伙伴可参考一下我之前的k8s系列文章:【k8s系列】从0到1搭建一个破产版的k8s集群流程了解一下。在 Kubernetes 中安装 Jenkins 通常有两种方式:
-
使用 Helm Chart 安装:Helm 是 Kubernetes 的包管理工具,可以简化复杂应用的部署过程。
-
使用 Kubernetes YAML 文件手动部署:直接创建 Kubernetes 资源(如 Pods、Deployments、Services 等)来部署 Jenkins。
由于Helm Cahrt需要进行安装,所以本次咱们在相关知识基础不足的情况下已手动部署的方式进行安装。下面是Kubernetes集群上逐步设置Jenkins的过程:
Step1:准备nfs服务
首先需要创建一个单独的命名空间,然后需要设置Jenkins的文件存储点,这块我使用k8s的pv进行存储数据(也可以使用storage class对象来自动创建)。创建pv需要使用nfs,这里咱们直接在master节点搭建nfs服务就行了:
root@master01:/opt/jenkins# kubectl create namespace jenkins
namespace/jenkins created
root@master01:/opt/jenkins# apt-get install rpcbind
正在读取软件包列表... 完成
正在分析软件包的依赖关系树... 完成
正在读取状态信息... 完成
下列软件包是自动安装的并且现在不需要了:
libwpe-1.0-1 libwpebackend-fdo-1.0-1
使用'apt autoremove'来卸载它(它们)。
下列【新】软件包将被安装:
rpcbind
升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 64 个软件包未被升级。
需要下载 46.6 kB 的归档。
解压缩后会消耗 160 kB 的额外空间。
获取:1 http://mirrors.aliyun.com/ubuntu jammy/main amd64 rpcbind amd64 1.2.6-2build1 [46.6 kB]
已下载 46.6 kB,耗时 0秒 (95.7 kB/s)
正在选中未选择的软件包 rpcbind。
(正在读取数据库 ... 系统当前共安装有 218228 个文件和目录。)
准备解压 .../rpcbind_1.2.6-2build1_amd64.deb ...
正在解压 rpcbind (1.2.6-2build1) ...
正在设置 rpcbind (1.2.6-2build1) ...
Created symlink /etc/systemd/system/multi-user.target.wants/rpcbind.service → /lib/systemd/system/rpcbind.service.
Created symlink /etc/systemd/system/sockets.target.wants/rpcbind.socket → /lib/systemd/system/rpcbind.socket.
正在处理用于 man-db (2.10.2-1) 的触发器 ...
root@master01:/opt/jenkins# systemctl start rpcbind && systemctl enable rpcbind
Synchronizing state of rpcbind.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable rpcbind
root@master01:/opt/jenkins# systemctl status rpcbind
● rpcbind.service - RPC bind portmap service
Loaded: loaded (/lib/systemd/system/rpcbind.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2024-08-24 12:46:33 CST; 1min 24s ago
TriggeredBy: ● rpcbind.socket
Docs: man:rpcbind(8)
Main PID: 181317 (rpcbind)
Tasks: 1 (limit: 4546)
Memory: 588.0K
CPU: 8ms
CGroup: /system.slice/rpcbind.service
└─181317 /sbin/rpcbind -f -w
8月 24 12:46:33 master01 systemd[1]: Starting RPC bind portmap service...
8月 24 12:46:33 master01 systemd[1]: Started RPC bind portmap service.
root@master01:/opt/jenkins# apt-get install nfs
正在读取软件包列表... 完成
正在分析软件包的依赖关系树... 完成
正在读取状态信息... 完成
E: 无法定位软件包 nfs
root@master01:/opt/jenkins# apt-get install nfs-kernel-server
正在读取软件包列表... 完成
正在分析软件包的依赖关系树... 完成
正在读取状态信息... 完成
下列软件包是自动安装的并且现在不需要了:
libwpe-1.0-1 libwpebackend-fdo-1.0-1
使用'apt autoremove'来卸载它(它们)。
将会同时安装下列软件:
keyutils libevent-core-2.1-7 libnfsidmap1 nfs-common
建议安装:
open-iscsi watchdog
下列【新】软件包将被安装:
keyutils libevent-core-2.1-7 libnfsidmap1 nfs-common nfs-kernel-server
升级了 0 个软件包,新安装了 5 个软件包,要卸载 0 个软件包,有 64 个软件包未被升级。
需要下载 568 kB 的归档。
解压缩后会消耗 2,076 kB 的额外空间。
您希望继续执行吗? [Y/n] y
获取:1 http://mirrors.aliyun.com/ubuntu jammy/main amd64 libevent-core-2.1-7 amd64 2.1.12-stable-1build3 [93.9 kB]
获取:2 http://mirrors.aliyun.com/ubuntu jammy-updates/main amd64 libnfsidmap1 amd64 1:2.6.1-1ubuntu1.2 [42.9 kB]
获取:3 http://mirrors.aliyun.com/ubuntu jammy/main amd64 keyutils amd64 1.6.1-2ubuntu3 [50.4 kB]
获取:4 http://mirrors.aliyun.com/ubuntu jammy-updates/main amd64 nfs-common amd64 1:2.6.1-1ubuntu1.2 [241 kB]
获取:5 http://mirrors.aliyun.com/ubuntu jammy-updates/main amd64 nfs-kernel-server amd64 1:2.6.1-1ubuntu1.2 [140 kB]
已下载 568 kB,耗时 2秒 (252 kB/s)
正在选中未选择的软件包 libevent-core-2.1-7:amd64。
(正在读取数据库 ... 系统当前共安装有 218245 个文件和目录。)
准备解压 .../libevent-core-2.1-7_2.1.12-stable-1build3_amd64.deb ...
正在解压 libevent-core-2.1-7:amd64 (2.1.12-stable-1build3) ...
正在选中未选择的软件包 libnfsidmap1:amd64。
准备解压 .../libnfsidmap1_1%3a2.6.1-1ubuntu1.2_amd64.deb ...
正在解压 libnfsidmap1:amd64 (1:2.6.1-1ubuntu1.2) ...
正在选中未选择的软件包 keyutils。
准备解压 .../keyutils_1.6.1-2ubuntu3_amd64.deb ...
正在解压 keyutils (1.6.1-2ubuntu3) ...
正在选中未选择的软件包 nfs-common。
准备解压 .../nfs-common_1%3a2.6.1-1ubuntu1.2_amd64.deb ...
正在解压 nfs-common (1:2.6.1-1ubuntu1.2) ...
正在选中未选择的软件包 nfs-kernel-server。
准备解压 .../nfs-kernel-server_1%3a2.6.1-1ubuntu1.2_amd64.deb ...
正在解压 nfs-kernel-server (1:2.6.1-1ubuntu1.2) ...
正在设置 libnfsidmap1:amd64 (1:2.6.1-1ubuntu1.2) ...
正在设置 libevent-core-2.1-7:amd64 (2.1.12-stable-1build3) ...
正在设置 keyutils (1.6.1-2ubuntu3) ...
正在设置 nfs-common (1:2.6.1-1ubuntu1.2) ...
Creating config file /etc/idmapd.conf with new version
Creating config file /etc/nfs.conf with new version
正在添加系统用户"statd" (UID 132)...
正在将新用户"statd" (UID 132)添加到组"nogroup"...
无法创建主目录"/var/lib/nfs"。
Created symlink /etc/systemd/system/multi-user.target.wants/nfs-client.target → /lib/systemd/system/nfs-client.target.
Created symlink /etc/systemd/system/remote-fs.target.wants/nfs-client.target → /lib/systemd/system/nfs-client.target.
auth-rpcgss-module.service is a disabled or a static unit, not starting it.
nfs-idmapd.service is a disabled or a static unit, not starting it.
nfs-utils.service is a disabled or a static unit, not starting it.
proc-fs-nfsd.mount is a disabled or a static unit, not starting it.
rpc-gssd.service is a disabled or a static unit, not starting it.
rpc-statd-notify.service is a disabled or a static unit, not starting it.
rpc-statd.service is a disabled or a static unit, not starting it.
rpc-svcgssd.service is a disabled or a static unit, not starting it.
rpc_pipefs.target is a disabled or a static unit, not starting it.
var-lib-nfs-rpc_pipefs.mount is a disabled or a static unit, not starting it.
正在设置 nfs-kernel-server (1:2.6.1-1ubuntu1.2) ...
Created symlink /etc/systemd/system/nfs-client.target.wants/nfs-blkmap.service → /lib/systemd/system/nfs-blkmap.service.
Created symlink /etc/systemd/system/multi-user.target.wants/nfs-server.service → /lib/systemd/system/nfs-server.service.
nfs-mountd.service is a disabled or a static unit, not starting it.
nfsdcld.service is a disabled or a static unit, not starting it.
Creating config file /etc/exports with new version
Creating config file /etc/default/nfs-kernel-server with new version
正在处理用于 man-db (2.10.2-1) 的触发器 ...
正在处理用于 libc-bin (2.35-0ubuntu3.8) 的触发器 ...
root@master01:/opt/jenkins# systemctl start nfs-server && systemctl enable nfs-server
root@master01:/opt/jenkins# systemctl status nfs-server
● nfs-server.service - NFS server and services
Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; vendor preset: enabled)
Active: active (exited) since Sat 2024-08-24 12:48:43 CST; 48s ago
Main PID: 184536 (code=exited, status=0/SUCCESS)
CPU: 9ms
8月 24 12:48:43 master01 systemd[1]: Starting NFS server and services...
8月 24 12:48:43 master01 exportfs[184534]: exportfs: can't open /etc/exports for reading
8月 24 12:48:43 master01 systemd[1]: Finished NFS server and services.
#提示读取不到文件,给个最大权限,并重启
root@master01:~# chmod 777 /etc/exports
root@master01:~# ls -l /etc/exports
-rwxrwxrwx 1 root root 65 8月 24 13:37 /etc/exports
root@master01:~# systemctl restart nfs-server
root@master01:~# systemctl status nfs-server
● nfs-server.service - NFS server and services
Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; vendor preset: enabled)
Drop-In: /run/systemd/generator/nfs-server.service.d
└─order-with-mounts.conf
Active: active (exited) since Sat 2024-08-24 14:29:02 CST; 43s ago
Main PID: 288982 (code=exited, status=0/SUCCESS)
CPU: 12ms
8月 24 14:29:02 master01 systemd[1]: Starting NFS server and services...
8月 24 14:29:02 master01 systemd[1]: Finished NFS server and services.
#添加共享文件卷访问
root@master01:~# vi /etc/exports
root@master01:/data# cat /etc/exports
/data/jenkins-vloume 192.168.1.201(rw,sync,no_root_squash,no_subtree_check)
#运行更改
root@master01:~# exportfs -ra
#重启nfs服务
root@master01:~# systemctl restart nfs-server
#查看允许挂载信息
root@master01:~# showmount -e 127.0.0.1
Export list for 127.0.0.1:
/data/jenkins-vloume 192.168.1.201
然后对应的node节点也需要安装nfs和rpcbind后,绑定mater上的jenkins卷目录:
[root@node01 ~]# systemctl status nfs
● nfs-server.service - NFS server and services
Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled)
Active: active (exited) since 六 2024-08-24 13:18:04 CST; 1h 17min ago
Main PID: 42490 (code=exited, status=0/SUCCESS)
CGroup: /system.slice/nfs-server.service
8月 24 13:18:04 node01 systemd[1]: Starting NFS server and services...
8月 24 13:18:04 node01 systemd[1]: Started NFS server and services.
[root@node01 ~]# ping 192.168.1.200
PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data.
64 bytes from 192.168.1.200: icmp_seq=1 ttl=64 time=0.519 ms
64 bytes from 192.168.1.200: icmp_seq=2 ttl=64 time=1.20 ms
^Z
[1]+ 已停止 ping 192.168.1.200
[root@node01 ~]# showmount -e 192.168.1.200
clnt_create: RPC: Port mapper failure - Timed out
但是这里出了点小插曲,nfs一直连接不上,虽然网络没问题,但考虑到我这一个是Ubuntu对应的master,一个是Centos对应的node,可能防火墙对NFS流量有所限制,需要开放一下:
-
在 Ubuntu 上,使用以下命令检查并允许 NFS 流量:
root@master01:/data# ufw allow from 192.168.1.201 to any port nfs 规则已添加
-
在 CentOS 上,如果使用
firewalld
,可以运行以下命令:[root@node01 ~]# firewall-cmd --permanent --add-service=nfs success [root@node01 ~]# firewall-cmd --permanent --add-service=mountd success [root@node01 ~]# firewall-cmd --permanent --add-service=rpc-bind success [root@node01 ~]# firewall-cmd --reload success
如果使用的是
iptables
,可以添加如下规则:sudo iptables -A INPUT -p tcp --dport 2049 -j ACCEPT sudo iptables -A INPUT -p udp --dport 2049 -j ACCEPT
然后重新试一下:
[root@node01 ~]# showmount -e 192.168.1.200
rpc mount export: RPC: Timed out
[root@node01 ~]# mount -t nfs 192.168.1.200:/data/jenkins-vloume /data/jenkins-vloume/
[root@node01 ~]# df -h
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 894M 0 894M 0% /dev
tmpfs 910M 0 910M 0% /dev/shm
tmpfs 910M 11M 900M 2% /run
tmpfs 910M 0 910M 0% /sys/fs/cgroup
/dev/mapper/centos-root 17G 8.4G 8.7G 49% /
/dev/sda1 1014M 239M 776M 24% /boot
tmpfs 182M 12K 182M 1% /run/user/42
tmpfs 1.7G 12K 1.7G 1% /var/lib/kubelet/pods/58daccfa-4a0b-4134-a610-33aebcbdf9d2/volumes/kubernetes.io~projected/kube-api-access-lbs2d
tmpfs 1.7G 12K 1.7G 1% /var/lib/kubelet/pods/1e99d787-bcc8-4461-85fe-73f7ca55dcde/volumes/kubernetes.io~projected/kube-api-access-fnzdg
tmpfs 182M 0 182M 0% /run/user/0
192.168.1.200:/data/jenkins-vloume 29G 19G 9.1G 68% /data/jenkins-vloume
#node节点测试
[root@node01 ~]# cat >>/data/jenkins-vloume/test.txt<<EOF
> 测试一下
> EOF
[root@node01 ~]# ls -l /data/jenkins-vloume/
总用量 4
-rw-r--r-- 1 root root 13 8月 24 15:40 test.txt
#master节点
root@master01:/data# ls -l jenkins-vloume/
总计 4
-rw-r--r-- 1 root root 13 8月 24 15:40 test.txt
root@master01:/data# cat jenkins-vloume/test.txt
测试一下
虽然还是出现,但是可以进行挂载了,并且测试数据共享也没问题,咱们就忽略继续了~
Step2:创建 Jenkins Deployment配置
创建 persistent volume claim,以便 Jenkins 可以持久化数据:
root@master01:/opt/jenkins# vi jenkins-deployment.yaml
root@master01:/opt/jenkins# cat jenkins-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins #deployment名称
namespace: jenkins #命名空间
spec:
replicas: 1
selector:
matchLabels:
app: jenkins-server
template:
metadata:
labels:
app: jenkins-server
spec:
terminationGracePeriodSeconds: 10 #优雅停止pod
serviceAccount: jenkins #后面还需要创建服务账户
containers:
- name: jenkins
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkinsci/blueocean:1.25.7 #镜像版本
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080 #外部访问端口
name: web
protocol: TCP
- containerPort: 50000 #jenkins save发现端口
name: agent
protocol: TCP
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60 #容器初始化完成后,等待60秒进行探针检查
timeoutSeconds: 5
failureThreshold: 12 #当Pod成功启动且检查失败时,Kubernetes将在放弃之前尝试failureThreshold次。放弃生存检查意味着重新启动Pod。而放弃就绪检查,Pod将被标记为未就绪。默认为3.最小值为1
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
volumeMounts: #需要将jenkins_home目录挂载出来
- name: jenkinshome
subPath: jenkins
mountPath: /var/jenkins_home
env:
- name: LIMITS_MEMORY
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Mi
- name: JAVA_OPTS
value: -Xmx$(LIMITS_MEMORY)m -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 -Duser.timezone=Asia/Shanghai
securityContext:
fsGroup: 1000
volumes:
- name: jenkinshome
persistentVolumeClaim:
claimName: jenkins-pvc #这里将上面创建的pv关联到pvc上
Step3:创建持久化pv&pvc配置
除此以外,为了保证Jenkins持久化缓存数据,我们还需要创建了一个PV:
root@master01:/opt/jenkins# vi jenkins-pvc.yaml
root@master01:/opt/jenkins# cat jenkins-pvc.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-pvc
spec:
capacity:
storage: 2Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Delete
nfs:
#注意修改NFS挂载目录以及NFS Server,nfs后面的目录是nfs挂载的目录,因为pod会执行mount -t ip:/...所以后面是nfs挂载目录,而并非是宿主机的目录
server: 192.168.1.200
path: /data/jenkins-vloume
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: jenkins-pvc
namespace: jenkins
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
Step4:创建rbac权限用户配置
另外还需要一个拥有相关权限的serviceAccount的Jenkins用户,这里我们手动赋予Jenkins一些必要的权限,当然直接给cluster-admin的集群角色权限:
root@master01:/opt/jenkins# vi jenkins-rbac.yaml
root@master01:/opt/jenkins# cat jenkins-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: jenkins
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: jenkins
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["services"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list","watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: jenkins
namespace: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
Step5:创建jenkins服务svc配置
此时jenkins已经在内部可以访问了,但是还无法在外部访问,还需要一个svc的yaml文件:
root@master01:/opt/jenkins# vi jenkins-svc.yaml
root@master01:/opt/jenkins# cat jenkins-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: jenkins
labels:
app: jenkins
spec:
selector:
#注意标签对应deployment上的,不然会出现能运行,但是访问不了web的情况
app: jenkins-server
type: NodePort
ports:
- name: web
port: 8080
targetPort: web
nodePort: 30002
- name: agent
port: 50000
targetPort: agent
Step6:按先后顺序应用已创建配置
此时配置文件全部准备好,咱们可以先执行pv,然后在执行rbac,deployment和svc来启动jenkins的应用服务:
root@master01:/opt/jenkins# ls -l
总计 16
-rw-r--r-- 1 root root 2379 8月 24 15:46 jenkins-deployment.yaml
-rw-r--r-- 1 root root 615 8月 24 15:53 jenkins-pvc.yaml
-rw-r--r-- 1 root root 1116 8月 24 15:56 jenkins-rbac.yaml
-rw-r--r-- 1 root root 286 8月 24 16:00 jenkins-svc.yaml
root@master01:/opt/jenkins# kubectl apply -f jenkins-pvc.yaml
persistentvolume/jenkins-pvc created
persistentvolumeclaim/jenkins-pvc created
root@master01:/opt/jenkins# kubectl apply -f jenkins-rbac.yaml
serviceaccount/jenkins created
resource mapping not found for name: "jenkins" namespace: "" from "jenkins-rbac.yaml": no matches for kind "ClusterRole" in version "rbac.authorization.k8s.io/v1beta1"
ensure CRDs are installed first
resource mapping not found for name: "jenkins" namespace: "jenkins" from "jenkins-rbac.yaml": no matches for kind "ClusterRoleBinding" in version "rbac.authorization.k8s.io/v1beta1"
ensure CRDs are installed first
root@master01:/opt/jenkins# kubectl apply -f jenkins-deployment.yaml
error: resource mapping not found for name: "jenkins" namespace: "jenkins" from "jenkins-deployment.yaml": no matches for kind "Deployment" in version "v1"
ensure CRDs are installed first
root@master01:/opt/jenkins# kubectl apply -f jenkins-svc.yaml
service/jenkins created
最后检查一下应用情况,如果有问题在日志中查找:
root@master01:/opt/jenkins# kubectl get pvc -n jenkins
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
jenkins-pvc Bound jenkins-pvc 2Gi RWX 34m
root@master01:/opt/jenkins# kubectl get pv -n jenkins
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
jenkins-pvc 2Gi RWX Delete Bound jenkins/jenkins-pvc 34m
root@master01:/opt/jenkins# kubectl get deployment -n jenkins
NAME READY UP-TO-DATE AVAILABLE AGE
jenkins 1/1 1 1 18m
root@master01:/opt/jenkins# kubectl get service -n jenkins
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins NodePort 10.1.190.247 <none> 8080:30002/TCP,50000:31935/TCP 106m
NAME READY STATUS RESTARTS AGE
jenkins-f6497b78d-84g7t 1/1 Running 0 23m
可以看到启动成功后就能通过node地址+外部端口(我这块是192.168.1.201:30002)访问Jenkins了:
4. 云服务部署
许多云服务提供商(如AWS、Azure、Google Cloud)提供了托管的Jenkins服务或解决方案。用户可以通过云平台快速部署和管理Jenkins。这里由于条件有限,就不仔细说明了。
优点:
-
无需自行管理服务器和基础设施。
-
与云平台的其他服务集成方便。
-
自动扩展和高可用性。
缺点:
-
可能涉及额外的成本。
-
依赖于特定的云服务提供商。
5. 分布式部署
在分布式部署模式下,Jenkins Master负责管理和调度任务,而Jenkins Agent(或称为Slave)负责执行具体的构建任务。这种模式适用于大规模项目和需要并行处理多个构建任务的场景。这里同样由于条件有限,就不仔细说明了。
优点:
-
提高构建效率和并行处理能力。
-
分散负载,提高系统稳定性。
缺点:
-
配置和管理相对复杂。
-
需要额外的资源来运行Agent节点。
四、总结
目前呢,CI/CD已成为现代软件开发不可或缺的一部分,它通过自动化和持续改进,帮助团队更快、更可靠地交付高质量的软件。Jenkins作为实现CI/CD的重要工具,提供了强大的功能和灵活性,使得这一过程更加高效和易于管理。随着技术的不断进步和市场需求的快速变化,CI/CD的重要性将日益凸显,成为推动软件开发创新和成功的关键因素。因此呢,选择Jenkins的部署方式还应根据具体需求、团队技术栈和资源情况来决定。无论是独立服务器、Docker容器、Kubernetes集群、云服务还是分布式部署,Jenkins都提供了灵活的部署选项,以适应不同的使用场景和扩展需求。随着技术的发展和团队需求的变化,Jenkins的部署方式也将不断演进,以提供更高效、更可靠的持续集成和持续交付服务。
言尽于此,关于Jenkins的使用咱们日后再聊,本文对Jenkins部署方式的简单汇总过程中如有疏漏和不足,欢迎小伙伴补充~
参考链接如下:
Jenkins官方文档
Jenkins中文文档