Jenkins + Ansible 集成实战:把配置管理焊进流水线里
🔧 环境准备:先把家伙事儿备齐
Jenkins 和 Ansible 这俩工具,单拎出来大家都不陌生。但搁一块儿用的时候,很多人就犯迷糊了——插件怎么装?路径怎么配?Playbook 放哪?参数怎么传?
我先把环境这块说清楚,免得后面踩坑。咱们这套环境用的是 Ubuntu 24.04 LTS,别拿老版本 CentOS 来套,包管理器都不一样,踩坑了别来找我。
Ubuntu 24 上装 Ansible:
# 更新源
sudo apt update
# 装Ansible,Ubuntu 24的仓库里自带,版本不算最新但够用
sudo apt install ansible -y
# 验证一下
ansible --version
# 输出类似:
# ansible [core 2.16.x]
# config file = /etc/ansible/ansible.cfg
# configured module search path = ['/home/jenkins/.ansible/plugins/modules', ...]
# python version = 3.12.xUbuntu 24.04 自带 Python 3.12,Ansible 装完直接就能跑,不用折腾 Python 环境,这点比 CentOS 省心多了。如果你非要装最新版的 Ansible,可以用 pip 装:
sudo apt install python3-pip -y
pip3 install ansible --break-system-packages不过生产环境我一般不建议这么搞,--break-system-packages 这参数看着就心虚,用系统仓库的版本稳当些。
Jenkins 的安装:
Ubuntu 24 上装 Jenkins 也简单,但别直接 apt install jenkins,仓库里的版本可能比较旧。建议用官方源:
# 先装JDK,Jenkins 2.4xx版本需要JDK 17+
sudo apt install openjdk-17-jdk -y
# 加Jenkins官方源
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.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-stable binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
# 装Jenkins
sudo apt update
sudo apt install jenkins -y
# 启动并设为开机自启
sudo systemctl enable --now jenkins装完浏览器访问 http://你的IP:8080,按提示走初始化流程就行。
SSH 免密配置:
Jenkins 运行用户是 jenkins,你得确保这个用户能免密 SSH 到所有被管节点。不然 Playbook 一跑,全卡在输入密码那一步,直接超时挂掉。
# 切到jenkins用户
sudo su - jenkins -s /bin/bash
# 生成密钥对,Ubuntu 24默认用ED25519了,比RSA快还安全
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
# 把公钥推到目标机器
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@192.168.1.100这里有个坑,Ubuntu 24 的 ssh-copy-id 对 ED25519 密钥有时候会抽风,如果报错就手动把公钥内容追加到目标机器的 ~/.ssh/authorized_keys 里。还有,目标机器的 sshd_config 里确认 PubkeyAuthentication yes 是开着的,Ubuntu 24 默认是开的,但万一有人改过呢。
别嫌麻烦,这一步不做,后面全是白搭。
目标机器侧的底线要求:
Ansible 是无代理架构,不需要装客户端,但 Python 环境得有。Ubuntu 24 自带 Python 3.12,完全没问题。就怕那种用精简镜像起的容器或者云主机,Python 给阉割了,那 Ansible 的模块基本跑不起来,报错能让你怀疑人生。遇到这种情况,先 apt install python3 -y 补上再说。
🧩 插件安装:让 Jenkins 认识 Ansible
Jenkins 默认不认识 Ansible,得装插件。这步简单,但别跳过。
路径:管理 Jenkins → 插件管理 → 可选插件
搜索 Ansible,你会看到几个相关的插件,装这个就行:
Ansible plugin — 这是官方维护的,功能最全
装完之后重启 Jenkins。Ubuntu 24 上可以用 sudo systemctl restart jenkins,也可以在插件管理页面点"安装完成后重启并等待",影响范围小一些。
重启完了,怎么验证插件装好了?进 管理 Jenkins → Global Tool Configuration,滑到最下面,如果出现了 Ansible 的配置区域,就说明插件生效了。
⚙️ 全局工具配置:告诉 Jenkins Ansible 在哪
这一步很多人卡住。插件装了,但 Jenkins 不知道 Ansible 装在哪个目录下,调用的时候就会报 ansible: command not found。
进 管理 Jenkins → Global Tool Configuration,找到 Ansible 区域:
- 名称:随便起,建议带版本号,比如
ansible-ubuntu24,后面 Pipeline 里引用的时候好区分 - 路径:填 Ansible 的可执行文件所在目录
怎么找这个路径?
which ansible
# Ubuntu 24上一般输出:/usr/bin/ansible那路径就填 /usr/bin,注意是目录,不是文件本身。
如果你服务器上装了多个版本的 Ansible(比如用 virtualenv 隔离的),这里可以添加多个,名字区分开就行。Ubuntu 24 上用 python3 -m venv 创建虚拟环境很方便:
python3 -m venv /opt/ansible-venv
source /opt/ansible-venv/bin/activate
pip install ansible==2.16.0
deactivate这种情况下路径就填 /opt/ansible-venv/bin,Jenkins 会在这个虚拟环境里找 ansible。
📁 项目结构:Playbook 别乱扔
在正式创建 Job 之前,先说个事儿——Playbook 文件放哪。
我见过最离谱的做法,是直接把 Playbook 扔在 Jenkins 服务器的 /opt/ansible 目录下,改了也没记录,谁改的不知道,改了啥不知道。出了问题,几个人面面相觑。
正确做法:Playbook 进 Git 仓库。
推荐的项目结构长这样:
ansible-config-repo/
├── inventory/
│ ├── dev.ini
│ ├── staging.ini
│ └── prod.ini
├── group_vars/
│ ├── dev.yml
│ ├── staging.yml
│ └── prod.yml
├── playbooks/
│ ├── init-env.yml
│ ├── deploy-app.yml
│ └── rotate-logs.yml
├── roles/
│ ├── common/
│ ├── nginx/
│ └── java/
├── ansible.cfg
└── Jenkinsfile这样做的好处太多了。版本可追溯,变更可回滚,多人协作不冲突,Jenkins 拉代码的时候一把全带上。这就是配置即代码的思路,别嫌麻烦,后面你会感谢自己的。
顺便说一句,ansible.cfg 建议放仓库根目录,Ansible 会自动优先读取当前目录下的配置文件。内容大概这样:
[defaults]
inventory = inventory/prod.ini
host_key_checking = False
forks = 20
timeout = 30
log_path = /var/log/ansible.log
[privilege_escalation]
become = True
become_method = sudoUbuntu 24 上 sudo 默认需要密码,如果你配了免密 sudo 就不用管,没配的话后面 Jenkins 调用的时候得加 --become-password-file 参数。
🏗️ 自由风格项目:先跑通再说
新建一个自由风格项目,名字就叫 ansible-config-deploy 吧。
源码管理 选 Git,填你的 Playbook 仓库地址,分支填 main 或者 master,看你仓库默认分支叫啥。
构建环境 里勾选 "Provide Configuration files"(如果你有 ansible.cfg 需要注入的话),一般不用勾,因为 ansible.cfg 已经在仓库里了。
构建 部分,这是核心。点"增加构建步骤",选 Invoke Ansible Playbook:
| 配置项 | 填什么 | 说明 |
|---|---|---|
| Ansible installation | ansible-ubuntu24 | 选你全局配置里起的名字 |
| Playbook path | playbooks/deploy-app.yml | 相对于仓库根目录 |
| Inventory | 选择"File or host list",填 inventory/prod.ini | 也可以选"Inline content"直接写 |
| Credentials | 选你配置的 SSH 私钥 | 用于连接目标机器 |
| Extra parameters | -v --diff | 看详细输出和变更差异 |
这里有个细节,Credentials 那栏,你得提前在 Jenkins 的凭据管理里添加一个 SSH Username with private key 类型的凭据,把 jenkins 用户的私钥导进去。Ubuntu 24 上如果你用的是 ED25519 密钥,Jenkins 插件是支持的,没问题。
点保存,然后点"立即构建"。如果一切配置正确,控制台输出里你会看到 Ansible 的标准输出,绿色的 ok 和 changed,那叫一个舒坦。
🔥 Pipeline 才是正道:代码化你的配置流程
自由风格项目能跑通,但不够灵活。真正在生产环境用,还得是 Pipeline。Pipeline 可以把整个流程写进 Jenkinsfile,跟着代码走,版本可控,参数化也更方便。
下面这个 Jenkinsfile 是我实际在用的,精简了一下,核心逻辑都在:
pipeline {
agent any
parameters {
choice(name: 'ENV', choices: ['dev', 'staging', 'prod'], description: '目标环境')
string(name: 'VERSION', defaultValue: 'latest', description: '部署版本号')
choice(name: 'TAGS', choices: ['all', 'deploy', 'config', 'restart'], description: '执行标签')
booleanParam(name: 'DRY_RUN', defaultValue: false, description: '是否试运行')
}
environment {
ANSIBLE_DIR = "ansible-config-repo"
}
stages {
stage('拉取 Playbook 仓库') {
steps {
git branch: 'main', url: 'https://your-repo/ansible-config-repo.git'
}
}
stage('语法检查') {
steps {
sh """
cd ${ANSIBLE_DIR}
ansible-playbook playbooks/deploy-app.yml \
--syntax-check \
--inventory inventory/${params.ENV}.ini
"""
}
}
stage('执行 Playbook') {
steps {
script {
def extraArgs = ""
if (params.TAGS != 'all') {
extraArgs += " --tags ${params.TAGS}"
}
if (params.DRY_RUN) {
extraArgs += " --check --diff"
}
ansiblePlaybook(
playbook: "${ANSIBLE_DIR}/playbooks/deploy-app.yml",
inventory: "${ANSIBLE_DIR}/inventory/${params.ENV}.ini",
extraVars: [
env: "${params.ENV}",
version: "${params.VERSION}"
],
extraArgs: extraArgs,
colorized: true
)
}
}
}
stage('执行结果通知') {
steps {
script {
echo "部署完成,环境:${params.ENV},版本:${params.VERSION}"
}
}
}
}
post {
failure {
echo "❌ Playbook 执行失败,请检查日志!"
}
}
}逐个说几个关键点:
参数化构建 是精髓。ENV 控制目标环境,VERSION 控制部署版本,TAGS 控制跑哪些任务,DRY_RUN 是试运行开关。这样一套 Pipeline,开发测试生产环境都能用,不用建三个 Job。
语法检查 那个 stage 别删。这是保险绳,Playbook 语法有问题,在测试环境就拦住了,不至于跑到生产环境才报错。虽然 --syntax-check 只检查语法不检查逻辑,但总比没有强。
extraVars 是 Jenkins 和 Ansible 之间传参的桥梁。Jenkins 这边的参数,通过 extraVars 注入到 Ansible 的变量里,Playbook 里直接用 {{ env }}、{{ version }} 引用就行,非常丝滑。
DRY_RUN 这个参数强烈建议加上。--check --diff 组合拳,不会真正修改目标机器,但会告诉你"如果真跑了,会改成什么样"。生产环境部署前先跑一次 DRY_RUN,心里有底。
🧨 踩坑实录:这些坑我替你踩过了
坑一:Jenkins 用户找不到 ansible 命令
明明命令行手动跑没问题,Jenkins 里一跑就报 ansible: command not found。这是因为 Ubuntu 24 上 Jenkins 服务的环境变量和你登录 shell 的环境变量不一样。Jenkins 服务是通过 systemd 启动的,它不会读你的 .bashrc。
解决办法有两个。一是在 Global Tool Configuration 里把路径配对,Jenkins 插件会自动处理 PATH。二是如果用的是 Pipeline 的 sh 方式调用,在 Jenkinsfile 里手动加 PATH:
environment {
PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${env.PATH}"
}如果你是用 virtualenv 装的 Ansible,PATH 里还得加上虚拟环境的 bin 目录。
坑二:SSH 连接超时
Ansible 默认的 SSH 超时时间挺短的,目标机器如果响应慢(比如在跑高负载任务),就会超时断开。
在 ansible.cfg 里加上:
[ssh_connection]
timeout = 30
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=noControlPersist 是 SSH 多路复用,连一次之后保持连接 60 秒,后续任务复用这个通道,速度能快不少。Ubuntu 24 的 OpenSSH 版本是 9.6,对 ControlPersist 支持很好,放心用。StrictHostKeyChecking=no 是防止首次连接时卡在确认指纹那一步,测试环境用没问题,生产环境慎用。
坑三:大批量执行时 Ansible 卡死
如果你 Inventory 里有几百台机器,Ansible 默认是分批执行的,但 fork 数默认只有 5。几百台机器排着队跑,那得跑到猴年马月。
改 ansible.cfg:
[defaults]
forks = 50具体设多少看你的 Jenkins 服务器配置和目标机器数量,别设太大,把网络和系统资源撑爆了。Ubuntu 24 默认的文件描述符限制是 1024,几百台机器并发连接可能会撞上这个限制,跑之前 ulimit -n 65535 调一下,或者改 /etc/security/limits.conf 永久生效。
坑四:Playbook 里用了 sudo 但没配免密
Ansible 需要 sudo 权限执行某些任务,但目标机器的 sudo 需要输密码。Ubuntu 24 上这个问题更常见,因为 Ubuntu 默认就是用 sudo 而不是 root 登录的。
两种解法:
一是在目标机器的 /etc/sudoers.d/ 下给部署用户加免密:
# 在目标机器上执行
echo "deploy ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/deploy
sudo chmod 440 /etc/sudoers.d/deploy用 /etc/sudoers.d/ 目录管理比直接改 /etc/sudoers 安全,不会把主配置文件搞乱。
二是在 Jenkins 的 Ansible 调用里加上 --become 和 --become-password-file 参数,指向一个存了 sudo 密码的文件。生产环境推荐第一种,安全一点的做法是用 Ansible 的 become 配合 sudo 免密。
坑五:Ubuntu 24 的 cgroup v2 导致某些 Ansible 模块异常
这个坑比较隐蔽。Ubuntu 24 默认用 cgroup v2,如果你用 Ansible 的 docker_container 模块管理容器,某些旧版本的 Docker 不兼容 cgroup v2,会导致模块执行失败。解决办法要么升级 Docker 到兼容版本,要么在 grub 里加启动参数切回 cgroup v1。不过这属于 Docker 的问题,跟 Ansible 本身关系不大,遇到了别往 Ansible 身上甩锅。
🛡️ 生产环境的几条铁律
Playbook 必须走 Git。 前面说过,不重复了。谁改了什么,什么时候改的,一键可查。出了事能回滚,比什么都重要。
测试环境验证完再上生产。 听起来是废话,但真正做到的团队没几个。我现在的做法是,Jenkins 里配两个 Job,一个跑 staging,一个跑 prod,prod 的 Job 加一个人工审批环节,必须点确认才往下走。多这一步,能挡住 80% 的低级错误。
敏感信息用 Ansible Vault 管。 数据库密码、API Key 这些东西,别明文写在 Playbook 里。用 ansible-vault encrypt 加密,Jenkins 调用的时候通过 --vault-password-file 传入解密密码。解密密码本身存在 Jenkins 的凭据管理里,别写死在 Jenkinsfile 上。
Ubuntu 24 上用 ansible-vault 没什么特别的,命令都一样:
# 加密敏感变量文件
ansible-vault encrypt group_vars/prod/vault.yml
# 编辑加密文件(会提示输入密码)
ansible-vault edit group_vars/prod/vault.ymlJenkins Pipeline 里调用的时候,把 vault 密码存成一个文件,路径传给 ansiblePlaybook 的 vaultCredentialsId 参数,让它从 Jenkins 凭据里取密码,安全又方便。
定期清理过期的 Inventory。 机器下线了但 Inventory 里还留着,Ansible 跑到一半连不上,整个 Playbook 就挂了。养成习惯,机器下线同步更新 Inventory,或者用动态 Inventory(比如从 CMDB 或者云 API 自动拉取机器列表),省心很多。Ubuntu 24 上跑动态 Inventory 脚本没问题,Python 3.12 兼容性很好。
📝 总结
Jenkins 和 Ansible 的集成,说白了就是让 Jenkins 当调度中心,Ansible 当执行引擎。Jenkins 负责触发时机、参数管理、流程编排、结果通知;Ansible 负责在目标机器上干活。各司其职,配合默契。
核心步骤就四步:装插件 → 配路径 → 写 Playbook 进 Git → 建 Pipeline 跑起来。听着简单,但每一步都有细节容易翻车。Ubuntu 24 上环境变量、SSH 免密、sudo 权限、cgroup 兼容性,这些小问题叠加起来,够你折腾一整天的。
自动化配置管理这事儿,早做早享受。别等到半夜被报警叫起来,才发现手动运维的苦。把重复的活交给机器,把时间留给更有价值的事情,这才是运维该有的样子。
如果这篇文章对你有帮助,点个赞👍,点个在看👀,转发给你们群里的兄弟们。你们的支持就是我持续输出的动力!
公众号:耕云躬行录
个人博客:躬行笔记