ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ansible离线安装全攻略:内网环境下的依赖处理与部署实战

Ansible离线安装全攻略:内网环境下的依赖处理与部署实战 干运维这行的谁没被内网环境折磨过。生产网段物理隔离、安全等保要求不许连外网、客户现场只有一台裸机和一张光盘偏偏领导丢过来一句把自动化运维搞起来。这时候你才发现Ansible这东西装起来其实不复杂复杂的是在没网的环境里把它装明白。我这些年经手过的离线部署场景五花八门从CentOS 7到Ubuntu Server从龙蜥到麒麟甚至还有Windows上跑WSL当控制端的。折腾得多了慢慢总结出一套傻瓜式的离线安装方法。这套方法不敢说百分之百通吃所有系统但只要你手里有一台能联网的机器、一个U盘基本就能搞定九成以上的Linux发行版。今天把这些经验整理出来包括当时踩过的坑和思考过程给正要被离线环境折磨的朋友一个参考。1. 先把离线安装的思路理清楚1.1 搞清楚控制端和受控端的区别很多人一上来就问Ansible怎么离线装其实这个问题得分两半看。Ansible架构里有一台控制机跑ansible命令的机器和若干台受控机被管理的目标机器。受控机其实不用装Ansible只要装了Python和SSH服务就行这俩在几乎所有的Linux发行版里都是默认自带或者随手能装的。真正需要费劲去装的只有控制端那一台机器。说句实在话很多人被离线安装Ansible吓住是因为脑子里想的是每台机器都要装一遍。实际上Ansible默认走SSH协议控制端通过SSH连过去执行Python脚本被管机器上根本不需要有Ansible的痕迹。所以你的重点只有一件事在控制端把Ansible装好。还有一个容易踩的误区是用pip装还是用yum装。如果你用的发行版是CentOS、RHEL这类Red Hat系系统自带的Python版本通常比较老比如CentOS 7是Python 2.7而新版Ansible对Python 3的要求越来越高。我建议干脆直接用系统的包管理器装老版本Ansible或者用Python 3的pip装新版本。这个选择直接影响后面离线包怎么准备得先定下来。1.2 离线环境的分层思路包管理器优先离线安装的核心矛盾说白了就是软件依赖关系。缺啥补啥这个思路用在一台裸机上就是灾难。比如你用pip装Ansible它依赖cryptography、PyYAML、Jinja2这些库cryptography又依赖OpenSSL的底层库一层套一层。如果你一个个手动去官网下载光梳理依赖树就能耗掉一下午。所以我做离线安装的时候心里有个优先级能用系统包管理器解决的问题绝不手动装系统包管理器解决不了的才用pip或者源码编译兜底。这样做的好处有三个系统包管理器能自动解决依赖你只需要在联网机器上用一条命令把要装的包连同依赖一起下载下来系统包和系统库的兼容性是发行版厂商帮你测试过的踩坑概率小维护起来省心以后想卸载、升级都有迹可循比如在CentOS上你可以用yumdownloader把ansible和它的依赖全部拉下来在Ubuntu上可以用apt-get的--download-only选项。这些命令都只需要联网跑一次然后把下载好的rpm包或者deb包拷贝到内网机器上就能装了。1.3 确定你的环境矩阵动手之前先把下面这张表填好后面会省很多事项目需要确认的内容控制端操作系统CentOS 7/8、Ubuntu 18.04/20.04/22.04、龙蜥、麒麟或其他控制端架构x86_64、ARM64aarch64还是其他控制端Python版本2.7、3.6、3.8还是更高受控端系统是否需要区分多种发行版网络隔离程度完全物理隔离还是仅禁止访问外网内网有镜像源受控端数量几台还是几十台要不要批量推送配置这些信息决定了你走哪条安装路线。比如控制端是ARM64架构的麒麟系统那你在x86的联网机器上下载rpm包就得留意架构问题用yumdownloader的时候要加--archaarch64之类的参数。又比如内网其实有镜像源只是不能出网那你直接把yum源指向内网镜像就行不用走U盘拷贝这条路。填完这张表你对离线安装的工作量就有数了。2. 核心实操四类离线安装方法详解2.1 用系统包管理器搞定依赖CentOS / RHEL系列这是最常规的一种情况。你找一台同样系统版本、同样架构的联网机器执行# 先装yumdownloader工具 yum install -y yum-utils # 创建一个目录存放下载的包 mkdir -p /root/ansible-offline cd /root/ansible-offline # 下载ansible及所有依赖 yumdownloader --resolve ansibleyumdownloader --resolve的意思是把ansible连同它依赖的包全部下载到当前目录。下载完之后把整个目录拷贝到离线机器上然后执行cd /root/ansible-offline rpm -ivh *.rpm如果离线机器上已经有部分依赖比如openssl已经装了rpm会提示冲突或者already installed这时候用--force参数或者直接改成rpm -Uvh *.rpm就行。实测下来更稳妥的做法是rpm -Uvh *.rpm --nodeps--nodeps的意思是跳过依赖检查因为我们下载的时候已经把依赖下载全了再检查一遍纯属浪费时间。Ubuntu / Debian系列Ubuntu的思路完全一样用的命令不同# 在联网机器上 apt-get install -y --download-only ansible # 下载的deb包会存放在/var/cache/apt/archives/目录下 mkdir -p /root/ansible-offline cp /var/cache/apt/archives/*.deb /root/ansible-offline/在离线机器上安装cd /root/ansible-offline dpkg -i *.deb可能出现的报错是dependency problems这说明依赖没下载全。解决办法是在apt-get install --download-only的时候顺手把ansible的依赖清单打出来看看缺哪个用apt-get download单独拉哪个。2.2 用pip解决Python生态的依赖系统包管理器虽然好但有时候版本太老。比如你想用Ansible 2.10以上的版本CentOS 7自带的yum源里可能只有2.9甚至更老的版本。这时候就得靠pip出马。在联网机器上用pip下载Ansible及其所有Python依赖到本地目录pip download ansible -d /root/ansible-pip-offline如果系统的pip版本老建议先升级pip否则下载的时候会提示pip is being invoked by an old script wrapper之类的警告。到了离线机器上直接用pip安装本地目录里的包pip install --no-index --find-links/root/ansible-pip-offline ansible这两个参数的含义是--no-index告诉pip不要去PyPI上找包--find-links告诉它去本地目录找。这个组合是离线安装Python包的标配不只是Ansible你装任何Python第三方库离线包都能用这个思路。跟热词里那些python离线安装第三方库的场景完全是同一个套路。需要注意的问题有两个。第一如果你用root用户跑pip现在的系统会提示running pip as root然后警告externally-managed-environment如果是为了装系统级命令可以加--break-system-packages参数。第二Ansible本身对Python版本有要求比如Ansible 9要求Python 3.9以上所以离线机器上的Python版本不能太老。2.3 源码编译安装兜底方案源码编译是最后手段因为它耗时最长、最容易出幺蛾子。但有些极端情况比如你想要某个特定版本的Ansible系统源里没有pip源里也没有现成的wheel包就只能走这条路。源码安装Ansible的流程是# 在联网机器上 git clone https://github.com/ansible/ansible.git cd ansible git checkout stable-2.9 # 按需切换到目标版本 # 把整个目录打包 cd .. tar czf ansible-src.tar.gz ansible到离线机器上解压后编译安装tar xzf ansible-src.tar.gz cd ansible python setup.py install源码编译最大的坑在于它编译过程中可能需要额外的编译工具链gcc、make等这些工具在离线环境里本身又可能缺失。所以走这条路之前先在离线机器上执行yum groupinstall Development Tools或apt install build-essential如果没网装不了那就得在下载rpm包的时候把这些工具也一并带上。说实话我基本不推荐源码装Ansible除非你有特殊需求或者闲着没事想折腾。2.4 手动拷贝法最笨但最透明的方案还有一种土办法是直接从一台已经装好Ansible的机器上把整个Python环境打包拷过去。比如你在A机器上装好了Ansible目录是/usr/bin/ansiblePython包在/usr/lib/python3.6/site-packages/ansible。你可以把这些路径下的文件全部打包到新机器上解压到同样的位置。这种方法简单粗暴但风险很大。比如两台机器的Python版本不一致或者系统的glibc版本差太多拷贝过去就是用不了。我实测过的经验是这种方法只在两台机器操作系统版本完全一致的情况下才能成功。如果你管理的是同批采购的服务器系统镜像都一样那这套方案效率奇高一条scp命令就能把整个环境推过去。3. 本地软件仓库离线安装的进阶玩法3.1 建一个自己的Yum源如果只是装一台控制端前面那些方法足够了。但如果你的内网环境里有几十台、上百台机器都需要装Ansible或者以后还要装别的软件我建议你直接在内网搭一个本地软件仓库。这相当于一次打包终身受用属于性价比极高的投资。方法是先在一台联网机器上把需要的rpm包全部下载下来然后打包带到内网机器上用createrepo工具生成仓库元数据# 先安装createrepo工具 yum install -y createrepo # 在存放rpm包的目录下生成repodata目录 cd /data/ansible-repo createrepo .然后把这台机器作为内网yum源其他机器通过nginx或者直接httpd共享这个目录客户端的repo文件配置成[ansible-local] nameAnsible Local Repo baseurlhttp://你的内网IP/ansible-repo enabled1 gpgcheck0这样内网其他机器上直接yum install ansible就行了不用再拷贝rpm包。这个思路跟离线装docker、离线装nginx其实一模一样——先把软件包准备好然后通过本地源分发。3.2 用pip download制作Python依赖包缓存如果你走pip路线也可以把相同理念发挥到极致。在内网机器上维护一个pip缓存目录所有机器安装Python包时都指定--find-links指向这个目录就行。更进阶的玩法是搭建一个本地PyPI镜像用devpi或者simpleindex工具但这就有点杀鸡用牛刀了。对大多数场景来说一个共享目录加上pip的参数指定就够了。4. 免密登录与安全基线配置4.1 配置SSH免密登录Ansible装好之后紧接着要做的一件事是配置SSH免密登录。Ansible本身基于SSH协议虽然支持每次执行都输入密码但那样做的话自动化程度就大打折扣了。比较正规的做法是生成密钥对并分发公钥。先停一下如果你觉得免密登录这个词太笼统我换个说法它的本质是把控制端的公钥放到受控端的~/.ssh/authorized_keys文件里。之后控制端连受控端时SSH会用私钥做身份验证不用再输入密码了。操作流程# 在控制端 ssh-keygen -t rsa -b 4096 # 分发公钥首次需要输入密码 ssh-copy-id root受控端IP在批量场景下你可以用Ansible自己来分发密钥这就解决了先有鸡还是先有蛋的问题。方法是在playbook里使用authorized_key模块- name: 分发SSH公钥 hosts: all tasks: - name: 添加公钥到authorized_keys authorized_key: user: root state: present key: {{ lookup(file, /root/.ssh/id_rsa.pub) }}前提是你至少已经能用密码登录一台机器然后用这台机器作为跳板去管理其他机器。第一次跑这个playbook的时候用-k参数输入密码之后就能全免密了。4.2 离线环境下的安全基线因为离线环境通常是内网隔离的很多人就觉得安全方面可以松懈。我见过不少内网服务器root密码极其简单甚至为空的这种习惯很不好。Ansible跑起来之后第一件事建议先把所有受控端的sshd配置加固一遍禁用root密码登录保留key登录、修改默认SSH端口、配置防火墙白名单等。这是Ansible的强项写个简单的playbook就能批量执行而且因为是一次配置永久生效后面基本不用管。离线环境不怕外部攻击但内部横向渗透的风险还是要在意的。5. 安装完成后的冒烟测试清单5.1 装完之后必须验证的几件事安装完成后别急着写playbook跑业务先做一遍冒烟测试确认环境真的没问题。我个人的测试顺序是这样的# 第一件事确认版本号 ansible --version # 第二件事确认能ping通受控端 ansible all -m pingansible all -m ping这个命令是Ansible的hello world它的工作原理是控制端通过SSH连到目标机器执行一个Python脚本然后把结果返回。如果能返回pong说明链路是通的SSH免密OK、Python环境OK、Ansible能执行远程命令。接下来可以试着跑一个实际点的模块比如setup模块收集受控端的硬件信息ansible all -m setup | grep ansible_processorsetup模块是Ansible里一个特别有用的模块它自动收集目标机器的操作系统版本、CPU、内存、硬盘、网卡等一大堆详细信息存放在称为facts的变量里。你后面写playbook的时候这些facts可以直接拿来用。比如根据系统版本走不同的安装分支或者根据CPU架构选择不同的软件包。5.2 常见报错速查表离线安装Ansible的过程中有几类报错几乎人人都遇到过我整理了一个速查表报错信息原因分析解决方法No package ansible availableyum源里没有ansible包确认epel-release是否安装使用epel源重新下载Could not find a version that satisfies the requirement ansiblepip找不到ansible确认pip源是否联网检查pip版本是否太老cryptography requires openssl 1.1.1系统OpenSSL版本太老用pip安装旧版本cryptography或升级系统OpenSSLModuleNotFoundError: No module named ansiblePython路径不对确认安装到了哪个Python环境下用对应python的pip重装[WARNING]: provided hosts list is emptyhosts文件里没写主机编辑/etc/ansible/hosts文件正确配置受控端IPPermission denied (publickey,password)SSH密钥没配好重新执行ssh-copy-id或者检查受控端的sshd配置Failed to connect to the host via ssh网络不通或SSH端口不对先测试ping和telnet 目标端口5.3 关于包版本锁定的一点体会离线环境有一个好处就是包版本不会因为时间流逝而变化——你的环境是冻结的。这在某种程度上是好事因为每次部署都是一模一样的版本不会出现昨天还能用的playbook今天突然跑不通的情况。但反过来如果安装的时候不记录版本号几个月后你根本不知道环境里装的是哪个版本的Ansible想复现环境就抓瞎了。我习惯在安装完之后把所有包的版本号导出到文件里存档pip freeze /root/ansible-packages.txt rpm -qa | grep ansible /root/ansible-rpm-list.txt ansible --version | head -1 /root/ansible-version.txt这样不管过了多久只要拿着这三个文件就能在联网机器上重新准备完全一致的环境。我自己的经验是Ansible离线安装这件事真正的难点不在于执行那几步命令而在于安装之前对环境的评估。你把系统版本、架构、Python版本、依赖情况摸清楚了后面就是照着方子抓药。另外每次做完离线部署我都建议把下载的rpm包和pip包保存好最好归到一个固定的目录里作为公司的资产。这些东西建一次后面就能一直复用。
返回列表