简介:gpmall-repo 是一份面向云计算与分布式电商平台搭建学习者的服务资源包,主要用于离线部署或内网环境中快速补齐系统依赖与中间件安装包,适合需要复现 gpmall 实验环境、练习服务端组件配置的初中级读者。压缩包共 173 个文件,整体约 304.19MB,其中 166 个 rpm 包构成核心软件仓库,涵盖 Java 运行环境、MongoDB、Logstash、Elasticsearch 等常用服务组件;另含 gz、bz2 压缩的仓库元数据与 1 个 xml 索引文件,便于构建本地 yum 源并完成依赖解析。已有 187 人学习下载。资源价值在于提供较完整的离线软件集合与仓库结构,读者可据此搭建本地源、减少外网依赖,并对照组件版本开展安装、启动与基础排错练习,适合作为云计算实验和电商项目环境准备的配套材料。
1. 一台没有外网的云主机,和一个离线源压缩包
在云计算场景里,最容易出问题的环节往往不是写代码,而是yum install。内网隔离、安全组只放业务端口、公网出口按流量计费,想装个编译工具链都可能卡在依赖解析上,最后变成手工rpm -ivh处理依赖冲突。gpmall-repo.rar 就是为这种场景准备的:它把一套商城系统部署所需的 RPM 包连同 repodata 元数据整体打包,解压后写一个.repo文件,本地目录就成了可用的软件源。适合两类人:要在隔离网络里搭完整商城环境的运维和后端;以及手里只有一台干净云主机、想把整套架构跑一遍的同学。
2. 解包 gpmall-repo.rar:repodata、rpm 清单与 .repo 三件套
动手之前先理清一件事:yum 或 dnf 安装软件包,靠的从来不是“文件夹里放着 rpm”,而是 repodata 目录下的元数据。repomd.xml记录了这一批包的名称、版本、依赖关系、校验值和文件清单,客户端先拉元数据做依赖求解,再去取对应的 rpm。所以一个能用的本地源,本质是三件套齐活:一堆 rpm 文件、一份与 rpm 严格对应的 repodata、以及客户端上一个指向该目录的.repo配置文件。缺任何一件,表现都是“源明明配了,就是装不上”。
2.1 解包与目录体检
先把包传上去。走内网跳板机 scp 或者云控制台的文件上传都行,rar 不适合断点续传,大文件建议先校验一下大小再传。落到目标机上之后按下面的顺序来,每一步都有它的意义,别跳过。
# 1) 确认文件落地且大小正常,避免上传中断拿到半个包 ls -lh gpmall-repo.rar # 2) 准备解压工具:unrar 在多数发行版要额外源,没有就用 7z yum install -y unrar || yum install -y p7zip p7zip-plugins # 3) 解压到固定路径,路径里不要有空格和中文,后面写 baseurl 会省很多事 mkdir -p /opt/gpmall unrar x gpmall-repo.rar /opt/gpmall/ # 用 7z 的话:7z x gpmall-repo.rar -o/opt/gpmall # 4) 体检:目录结构、rpm 数量、总体积、repodata 是否完整 ls -l /opt/gpmall find /opt/gpmall -name "*.rpm" | wc -l du -sh /opt/gpmall test -f /opt/gpmall/repodata/repomd.xml && echo "repodata OK"unrar x的x是保留目录结构解压,别用e,e会把所有文件摊平到同一层,repodata 和 rpm 混在一起直接废掉。7z的输出目录参数是-o且中间不能有空格,写成-o /opt/gpmall会把/opt/gpmall当成待压缩文件,这是新手最高频的一次翻车。最后那句test -f是我每次必跑的,返回空就说明这个包只有 rpm 没有元数据,后面得自己createrepo。
2.2 repodata 为什么不能靠手工拷 rpm 替代
很多人图省事,进目录rpm -ivh *.rpm一把梭。短期能装,长期是灾难:rpm 不解决依赖顺序,装到一半报Failed dependencies就得手工一个个补;升级时也不知道哪些包被谁依赖着。yum 走元数据,本质是把“依赖求解”这件苦力活交给机器,代价就是你得维护好 repodata。
如果解压出来发现 repodata 缺失,或者你往目录里补了新包,元数据就必须重建,否则客户端看到的是旧快照,新增的包永远搜不到:
# 安装元数据生成工具(若本地源里没有,先在能上网的机器上下好 rpm 带过来) yum install -y createrepo # 全量生成:会重写 repodata 目录 createrepo -v /opt/gpmall # 增量更新:只处理新增/变更的 rpm,速度快很多 createrepo --update /opt/gpmall-v是输出详细过程,包多的时候能看清卡在哪个文件上。--update不会删除已下架的旧包记录,如果整个仓库做了大换血,老老实实全量重建一次更稳。生成完再cat /opt/gpmall/repodata/repomd.xml | head -20看一眼 revision 时间戳是不是刚才,这是判断元数据新旧的唯一可靠办法。
2.3 写第一个 .repo 文件并让它生效
客户端配置放在/etc/yum.repos.d/下,文件名随意但必须以.repo结尾。仓库 ID 用中括号包起来,全局唯一,重复了会互相覆盖。
cat > /etc/yum.repos.d/gpmall-local.repo <<'EOF' [gpmall-local] name=GPMall Local Repository baseurl=file:///opt/gpmall enabled=1 gpgcheck=0 EOF # 清缓存 + 重建 + 看源是否被识别 yum clean all yum repolist allbaseurl=file:///opt/gpmall这里是三个斜杠,少一个就变成相对路径解析,直接报Cannot find a valid baseurl。gpgcheck=0是离线包的常见妥协,包来源可信就没问题;如果资源包里带了 GPG 公钥,改成gpgcheck=1并加一行gpgkey=file:///etc/pki/rpm-gpg/xxx更规范。目录权限保持 755,/opt/gpmall若是 700,yum 以普通用户执行时会读不到元数据。做完这三步,yum repolist里能看到gpmall-local且有包数量,源这一层就算通了。
3. file:// 还是 http://:单机源与内网共享源的参数差异
同一份目录,接法不同,适用场景完全不同。单机自用走file://,零依赖、零端口、最快;一旦要在云计算环境里给多台机器供源,就必须走http://,否则每台机器都得存一份几十 GB 的 rpm,镜像和备份成本立刻失控。选型不看喜好,看你有几台机器、是否跨可用区。
3.1 两种接法的差异对照
| 维度 | file:// 本地源 | http:// 内网源 |
|---|---|---|
| 适用规模 | 单机、临时排障 | 同一 VPC 内多机共享 |
| 额外依赖 | 无 | 需要 Web 服务(Nginx/Apache) |
| 端口与安全组 | 不涉及 | 需放通内网端口,禁止对公网开放 |
| 更新方式 | 直接改目录,yum clean all即可 | 改目录 + 检查 Web 根路径映射 |
| 性能 | 本地磁盘 IO,最快 | 受内网带宽与并发影响 |
| 典型故障 | 路径层级写错 | 403、SELinux、目录穿越被拦 |
我一般的判断标准很粗暴:只有一台机器要用,file://写完收工;只要出现第二台,第一天就把 http 源搭起来,不然后面做批量部署时一定会返工。
3.2 用 Nginx 把目录发布成内网源
Nginx 若没装,先从本地源里装,正好顺手验证源可用。配置里最关键的一句是root指向仓库根目录,而不是 repodata 目录,这个层级搞错就会 404。
server { listen 8088; server_name _; # root 指向仓库根,即 repodata 的父目录 root /opt/gpmall; # 打开目录索引,方便浏览器里核对包是否齐全 autoindex on; autoindex_exact_size off; location / { try_files $uri $uri/ =404; } }放通端口这一步按环境来,开了防火墙的执行下面两条,用云安全组的则在安全组里加一条仅限内网网段的入方向规则,源端口千万别对0.0.0.0/0开:
firewall-cmd --permanent --add-port=8088/tcp firewall-cmd --reload # 本机自检:能拿到 repomd.xml 就说明 Web 层通了 curl -sI http://127.0.0.1:8088/repodata/repomd.xml | head -1如果返回 403 而不是 404,先看目录权限是不是 755,再看 SELinux 是否拦了非标准目录:ls -Z /opt/gpmall看上下文,restorecon -Rv /opt/gpmall修一遍,仍然不行再考虑setsebool -P httpd_read_user_content 1。这条排查路径我踩过不止一次,血泪经验是:403 九成不是 Nginx 配置问题。
3.3 客户端切到 http 源并做一次真实验证
改配置之前先在客户端上确认网络可达,curl http://内网IP:8088/repodata/repomd.xml拿不到内容,后面全是白忙。
cat > /etc/yum.repos.d/gpmall-http.repo <<'EOF' [gpmall-http] name=GPMall Internal Mirror baseurl=http://10.0.0.12:8088/ enabled=1 gpgcheck=0 EOF yum clean all && yum makecache # 隔离验证:只启用这个源,排除公网源的干扰 yum --disablerepo="*" --enablerepo="gpmall-http" list available | head -30 # 装一个包到临时目录,验证下载链路完整但不污染系统 yum install -y --downloadonly --downloaddir=/tmp/verify redis--disablerepo="*"这一步是整套验证里最值钱的:公网源开着的时候,yum 会悄悄从别处补齐依赖,你以为本地源通了,实际一断网立刻原形毕露。--downloadonly需要yum-plugin-downloadonly,它只下载不安装,用来做链路自检最合适,类生产环境里也常这么干。两条都过了,才算这个源真的可用。
4. 按依赖顺序装中间件:从 JDK 到 Kafka 的版本矩阵与启动参数
商城类系统对中间件的依赖是有先后顺序的:数据库和缓存先起来,注册中心和消息队列随后,最后才是应用。顺序装反了,服务起来就疯狂重连甚至启动失败,日志刷屏但看不出原因。这一章先锁版本,再按顺序装,最后做一次统一体检。
4.1 动手前先拉版本矩阵
不要凭印象装。包里到底有哪些版本,用 rpm 查询命令直接看,比翻文档靠谱:
# 不安装也能列出包名与版本,输出重定向到文件方便比对 for p in /opt/gpmall/*.rpm; do rpm -qp --queryformat "%{NAME}\t%{VERSION}-%{RELEASE}\t%{ARCH}\n" "$p" done | sort > /tmp/pkg-list.txt # 看某个包声明了哪些依赖,提前判断会不会缺件 rpm -qpR /opt/gpmall/mysql-community-server-*.rpm | head -20--queryformat里的%{ARCH}一定要看,云主机里 ARM 实例并不少见,aarch64 的机器装 x86_64 的 rpm 会直接报架构不匹配。把输出整理成矩阵,后面部署时按图索骥:
| 组件 | 作用 | 默认端口 | 启动顺序 | 装前必看 |
|---|---|---|---|---|
| JDK | 应用运行环境 | 无 | 1 | 版本需与编译目标一致 |
| MySQL | 订单、商品主数据 | 3306 | 2 | datadir 磁盘余量与字符集 |
| Redis | 缓存、会话、分布式锁 | 6379 | 3 | 密码与绑定地址 |
| Nginx | 静态资源与反向代理 | 80/443 | 4 | 与后端 upstream 一致 |
| Zookeeper | 注册中心 | 2181 | 5 | 集群需奇数节点 |
| Kafka | 订单异步消息 | 9092 | 6 | 依赖 ZK,堆内存别给太大 |
在云计算环境里,这张表还有一列隐含信息:哪些端口能被安全组放通。3306、6379、2181、9092 这些一律只对内网网段开放,公网只留 80/443,这条比任何配置优化都重要。
4.2 装 JDK、MySQL、Redis 与关键参数
JDK 先装,因为它不依赖任何东西;MySQL 和 Redis 都依赖系统库,放中间装。下面是能直接抄的一段:
# JDK:装完立刻验证版本,避免系统里存在多个 java 导致启动用错 yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel java -version && javac -version # MySQL:首次启动会做初始化,注意看临时密码写到了哪个日志 yum install -y mysql-community-server systemctl enable --now mysqld grep 'temporary password' /var/log/mysqld.log # 改三项最常被忽略的配置再重启 cat >> /etc/my.cnf <<'EOF' bind-address = 0.0.0.0 character-set-server = utf8mb4 default-time-zone = '+08:00' EOF systemctl restart mysqld # Redis:默认只监听回环且无密码,必须改 yum install -y redis sed -i 's/^bind 127.0.0.1/bind 0.0.0.0/' /etc/redis.conf sed -i 's/^# requirepass foobared/requirepass YourStrongPass/' /etc/redis.conf systemctl enable --now redis redis-cli -a YourStrongPass ping逐条说清楚为什么这么改。bind-address=0.0.0.0是为了让应用服务器能连过来,但必须配合安全组限制来源网段,否则等于把库暴露在公网上,这是最典型的后悔药场景。utf8mb4而不是utf8,是因为商品标题里的表情符号和生僻字用三字节编码存不住,会在插入时被截断或报错。default-time-zone不设,容器里默认 UTC,订单时间和报表全对不上,排查起来极其玄学。Redis 那边protected-mode在绑定非回环地址后会拒绝外部连接,改完bind记得确认这一项的状态。
4.3 装完不等于装对:一次统一体检
服务都 start 了不代表能用。下面这组检查我每次部署完都会跑,能提前发现八成问题:
# 1) 端口是否真的在监听(有些服务启动成功但只监听本地) ss -lntp | grep -E '3306|6379|2181|9092|80|8088' # 2) 有没有启动失败但被忽略的单元 systemctl --failed # 3) 关键目录的磁盘与内存余量 free -m; df -h /var/lib/mysql # 4) 文件句柄,Kafka 和 ES 类组件最容易在这里翻车 ulimit -n # 5) 依赖 mmap 的组件需要提高内核参数 sysctl -w vm.max_map_count=262144 echo 'vm.max_map_count=262144' >> /etc/sysctl.confss -lntp里的-p需要 root,它能把端口和进程对上,避免“端口占着但进程是老的”这种假活状态。systemctl --failed一句话能省半小时,很多组件启动失败后 systemd 只是标个 failed,不主动看根本发现不了。ulimit -n默认 1024,消息队列在压测时会出现Too many open files,部署阶段就调上去比线上救火便宜得多。
5. 避坑记录:五个让本地源当场失效的细节
本地源这个东西,配通了很无聊,配不通很折磨,因为报错信息往往指向不了真正的原因。下面五条是我在实际环境里反复遇到的,按“现象 → 原因 → 解决”整理,建议对着排。
5.1 源能识别但装不上:三条例行排查
第一,repolist里能看到源名,包数量却是 0。现象很迷惑,源明明 enabled 了。原因基本是baseurl的路径层级错了,file:///opt/gpmall被写成了file:///opt/gpmall/repodata,客户端在 repodata 目录下再找 repodata,自然什么都没有。解决办法是cat /opt/gpmall/repodata/repomd.xml | head -3确认文件真实存在,并把 baseurl 回退到 repodata 的父目录,然后yum clean all强制重读。
第二,报Failed to download metadata for repo。这通常发生在你往目录里补了新 rpm,但 repodata 还是旧的,元数据里记录的校验值和实际文件对不上,或者元数据引用的某个包已经被删。解决方式是createrepo --update /opt/gpmall重建,然后清缓存重试;如果仓库整体换过版本,直接全量createrepo更省事。顺带检查du -sh /opt/gpmall/repodata,元数据异常小往往意味着生成过程被中断过。
第三,包明明在目录里,yum install却说找不到。先看架构:uname -m输出 aarch64 而包里全是 x86_64,这种情况一个都装不上。再看包名是否带-devel之类的后缀差异,用yum --disablerepo="*" --enablerepo=gpmall-local search 关键字精确搜一遍。还有一种隐蔽情况是仓库里有同名不同版本的多个包,priority插件没装导致源之间互相打架,装个yum-plugin-priorities并给本地源设priority=1就能压住。
5.2 包装完了服务起不来:两条环境类坑
第四,Nginx 下访问源目录返回 403,但本机curl有时又通。现象是浏览器能列出目录、客户端下载却失败。原因多半是 SELinux 上下文不对,/opt下的自建目录不在 httpd 的可读策略里;另一种是目录权限 700,Nginx worker 以普通用户运行读不到。解决顺序是chmod -R 755 /opt/gpmall→restorecon -Rv /opt/gpmall→ 仍不行再setsebool -P httpd_read_user_content 1,最后tail -f /var/log/nginx/error.log确认不再是权限类报错。
第五,MySQL 或 Redis 装完启动失败,日志里是权限或路径类错误。典型是Can't create/write to file,原因分为两类:一是datadir被改到了挂载盘而目录属主不是 mysql,二是云主机上数据盘刚挂载、文件系统还没初始化就用上了。解决是chown -R mysql:mysql /var/lib/mysql(Redis 对应chown redis:redis),确认/etc/my.cnf里的datadir与实际路径一致,再看systemctl status mysqld -l和/var/log/mysqld.log的最后 30 行。这里别急着rm -rf数据目录重来,先确认是权限问题还是初始化没跑完,两者的处理方式完全不同。
6. 把手工步骤收敛成一个自检脚本:源目录的复用与校验
手工配一次源不费劲,费劲的是三个月后换一台机器重来一遍,还得凭记忆复现当时的路径和参数。我一般的做法是把“源是否健康”这件事写成脚本,跟仓库目录放在一起,谁接手都能一条命令看清楚:
#!/usr/bin/env bash # 本地源健康自检:路径、元数据、包数量、Web 可达性四项 REPO_DIR=${1:-/opt/gpmall} HTTP_URL=${2:-} [ -d "$REPO_DIR" ] || { echo "目录不存在: $REPO_DIR"; exit 1; } [ -f "$REPO_DIR/repodata/repomd.xml" ] || { echo "缺少 repodata,请先 createrepo"; exit 1; } echo "rpm 数量: $(find "$REPO_DIR" -name '*.rpm' | wc -l)" echo "仓库体积: $(du -sh "$REPO_DIR" | cut -f1)" echo "元数据时间: $(stat -c %y "$REPO_DIR/repodata/repomd.xml")" if [ -n "$HTTP_URL" ]; then code=$(curl -s -o /dev/null -w '%{http_code}' "$HTTP_URL/repodata/repomd.xml") echo "HTTP 状态: $code" # 期望 200;403 查权限与 SELinux,404 查 root 层级 fi把它存成/opt/gpmall/check-repo.sh,chmod +x之后随时跑。比脚本本身更有价值的是那个习惯:每次往仓库里加包,先跑一遍自检,再改客户端配置。顺序反过来,你面对的永远是“客户端报错 + 源状态未知”两个变量,排查成本翻倍。
再补一个复用技巧:仓库目录稳定之后打个 tar 包丢到内网文件服务器或对象存储,新机器直接拉下来解压,比重新传 rar 再解压快得多,也避开了 rar 工具在部分发行版上装不上的问题。tar 打包时加--numeric-owner保持属主数字,避免跨机 UID 映射错乱。从那以后我每次交付离线环境,都会把这份自检脚本和仓库一起打包,并在 README 里写清 baseurl 该填什么、端口开哪个网段——这比口头交接靠谱得多。希望帮到你。
本文还有配套的精品资源,点击获取