ARTICLE DETAIL

资讯详情

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

Apollo分布式配置中心Linux环境部署实战指南

Apollo分布式配置中心Linux环境部署实战指南 在 Linux 服务器上部署 Apollo表面上看就是解压三个发行包、改几行数据库连接、跑一下 startup.sh 的事但真正动手操作过的人都知道配置和启动这两步之间隔着不少坑。尤其是有过 Windows 上 Quick Start 跑通经验的人一到 Linux 手动部署就很容易遇到服务进程起来了但就是访问不了这种玄学问题。Quick Start 帮你隐藏了太多细节生产环境手动部署绕不开那套组件关系和端口规划。Apollo 是携程开源的分布式配置中心在 Java 微服务、Kubernetes 集群、多环境配置管理这些场景下用得非常多。它不会像 Spring Cloud Config 那样把配置丢在 Git 仓库里让各应用自己拉而是通过服务端集中管理、客户端实时感知变更。这篇博文就围绕 Linux 环境下的完整部署链路展开从环境准备、数据库初始化、发行包配置、启动验证到启动失败排查都会过一遍适合第一次在 Linux 上部署 Apollo 的运维和开发同学也适合想搞懂 Apollo 启动机制、准备自己封装部署脚本的人。1. 部署前先理清 Apollo 的三个服务和两套库别当黑盒直接跑1.1 Config Service、Admin Service、Portal 各管什么Apollo 不是单体应用官方发行包拆成了三个独立服务。很多人一上来就急着下载配置结果连我到底在启动几个进程都没概念。先把职责理清楚后面配 IP 和端口的时候才不会乱。Config Service直译是配置服务核心职责是面向客户端提供配置读取接口。微服务里的每个应用启动的时候都会通过 Config Service 拉取自己的配置后续配置变更也是由 Config Service 推送或客户端轮询获取。你可以把它理解为对外暴露的读配置的大门所有业务应用的客户端请求都会打到这个服务上。为了支撑大量客户端Config Service 在实际部署中可以横向扩展出多个实例挂在负载均衡后面。Admin Service管理服务面向的是 Portal 管理端和 Open API。创建项目、修改配置、发布配置、回滚配置这类写操作Portal 都会通过 Admin Service 去执行。为什么要单独拆一个服务因为 Apollo 的设计理念里读写分离很重要——客户端高频读配置走 Config Service管理端低频写配置走 Admin Service两边互不影响也能各自做鉴权和流量控制。Portal 是门户管理界面它本身不直接读写数据库也不直接面对配置客户端而是对接多个环境的 Admin Service。你在浏览器里看到的 Web 管理页面就是它。这里有一个很关键的设计一套 Portal 可以管理多套环境dev、fat、uat、prod这也是 Apollo 最初的核心卖点之一——集中管理多环境配置而不是每个环境单独搭一套管理后台。1.2 ConfigDB 和 PortalDB 的分工以及被忽略的 EurekaApollo 一共需要两个数据库ApolloConfigDB 和 ApolloPortalDB。新手最容易犯的错是把所有表都导进一个库或者只初始化了其中一个然后报各种Table not found的错。ApolloConfigDB 是核心库存每个环境的配置数据包括 App、Cluster、Namespace、Item、Release 这些表。客户端每次拉到的配置归根到底都来自这个库。如果是多环境部署原则上每个环境都要有一个独立的 ApolloConfigDB。比如 dev 环境一套prod 环境一套绝对不能共用。ApolloPortalDB 存的是 Portal 自身的业务数据包括用户信息、权限关系、项目元数据、操作审计等。它相当于 Apollo 管理端自己的后台数据库。注意PortalDB 是全环境共享的一套 Portal 配一个 PortalDB 即可。还有一个隐形成员很容易被忽略——Eureka。Apollo 的服务注册与发现是内置 Eureka 实现的。Config Service 和 Admin Service 启动后会自动注册到 Eureka 上Portal 也是通过 Eureka 来发现各环境的服务地址。理解了这一点你就明白为什么后面配置里到处都是eureka.service.url也就能理解为什么启动失败经常表现为服务进程在但管理页面看不到已注册的实例。2. 环境准备从建库、导表到 JDK 与内存评估2.1 MySQL 版本与字符集别等配置成了问号才回头Apollo 对 MySQL 的版本要求不算苛刻5.7 及以上、8.x 都没问题但有两个细节必须注意。一是字符集。Apollo 官方表结构脚本默认用的是 utf8mb4如果你建库时用了 latin1 或者 utf8中文配置项存进去后轻则显示乱码重则直接写入失败或者客户端拉到的中文变成问号。我习惯在建库时就显式指定CREATE DATABASE ApolloConfigDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE DATABASE ApolloPortalDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;另外如果服务器上已经有一个老库里面数据和字符集都已经是现实的存量千万不要手工去改库字符集更稳妥的做法是新建库、导入数据、切换连接串把旧库保留作回退。二是时区。Apollo 服务端连接 MySQL 时JDBC URL 里如果不带 serverTimezone 参数在 MySQL 8.x 下大概率会报时间相关的异常比如The server time zone value CST is unrecognized。这个坑在部署阶段非常常见建议数据库连接串直接写成jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncodingutf8serverTimezoneAsia/Shanghai2.2 建用户、导表结构脚本是现成的别自己手工建表我建议单独创建一个数据库账号给 Apollo 用不要直接用 root 到处跑。以 MySQL 8.x 为例CREATE USER apollo% IDENTIFIED BY YourStrongPassword; GRANT ALL PRIVILEGES ON ApolloConfigDB.* TO apollo%; GRANT ALL PRIVILEGES ON ApolloPortalDB.* TO apollo%; FLUSH PRIVILEGES;版本升级时不要直接对整个库跑新版本的初始化脚本Apollo 的升级脚本是增量式的放在 migration 目录下按版本号分目录存放全量脚本覆盖很容易把已有配置弄丢。这点我在生产环境升级时吃过亏全量导了一次旧环境的配置直接被清空还好当时有备份。2.3 JDK 版本与内存评估太小气的机器跑不动Apollo 服务端是 Java 应用部署前需要确认服务器上装了 JDK。生产环境建议用 JDK 8 或 11不同版本 Apollo 的兼容性有差异我用得最多的是 Apollo 1.9.x在 JDK 8 下最稳。查看版本java -version没有 JDK 的话用 OpenJDK 也行sudo apt install openjdk-8-jdk # Debian/Ubuntu sudo yum install java-1.8.0-openjdk # CentOS/RHEL内存方面Apollo 三个服务默认的 JVM 堆设置并不算小。如果不调直接启动一台 2G 内存的机器很容易在启动阶段就卡死甚至 OOM。下面这种场景很典型物理机内存只有 2G三个服务叠加大约要吃掉 1.5G2G加上 MySQL 自己还要占内存结果就是 Java 进程起来了MySQL 挂了或者三个服务互相拖垮。所以启动前建议先看服务器内存free -h然后按实际资源调整后面章节会讲到的 JVM 参数。3. 手动部署三个服务配置项逐个拆开讲清楚3.1 获取发行包与目录规划生产环境不要用 Quick Start 那套那是 demo 级别的。我都是直接从 GitHub Releases 或国内镜像源下载三个 zip 包apollo-configservice-x.x.x-github.zipapollo-adminservice-x.x.x-github.zipapollo-portal-x.x.x-github.zip版本号一定要保持一致混用容易出现 API 不兼容。解压后每个目录的结构类似这样apollo-configservice/ ├── bin/ │ ├── startup.sh │ └── apollo-configservice.sh ├── config/ │ ├── application-github.properties │ └── apollo-env.properties ├── scripts/ │ └── sql/ │ └── apolloconfigdb.sql └── lib/建议把三个服务放到独立目录比如mkdir -p /opt/apollo/{configservice,adminservice,portal}各自解压进去方便后面做 systemd 托管或写启停脚本。目录规划这一步很容易被忽略等到后面升级、回滚、看日志的时候你就会发现良好的目录结构能省太多事。3.2 Config Service 的配置与 Eureka 端口Config Service 的配置主要在config/application-github.properties文件里。因为 Apollo 默认会读取application-github.properties这个文件所以一般不用改文件名直接在里面改内容即可。关键的配置项spring.datasource.url jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncodingutf8serverTimezoneAsia/Shanghai spring.datasource.username apollo spring.datasource.password YourStrongPassword eureka.service.url http://localhost:8080/eureka/这里有一个非常大的新手误区eureka.service.url不是让你填一个远程 Eureka 中心的地址而是 Config Service 和 Admin Service 互相注册的地址。因为 Apollo 把 Eureka 内嵌进来了每个服务启动后既会把自己注册到别的服务也接受别的服务注册到自己。所以 Config Service 的eureka.service.url通常就是它自己的地址加/eureka/端口默认 8080。Config Service 默认端口是 8080。如果服务器上已经有别的应用占了 8080要改server.port。注意改了端口之后eureka.service.url也要跟着改不然服务之间会找不到彼此。这一点我下面启动排查章节还会重点讲。3.3 Admin Service 和 Portal 的配置差异以及 Meta Server 的作用Admin Service 的配置逻辑几乎和 Config Service 一样只不过数据库还是指向 ApolloConfigDB默认端口是 8090。很多人想不通为什么两个服务用同一个库因为前面说了Config Service 是读配置的Admin Service 是写配置的它们面对的是同一份数据的读写两端用同一个库完全合理。Portal 的配置要稍微复杂一点因为它要管理多环境至少要改这几个地方spring.datasource.url jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncodingutf8serverTimezoneAsia/Shanghai spring.datasource.username apollo spring.datasource.password YourStrongPassword apollo.portal.envs dev apollo.portal.meta.servers http://localhost:8080apollo.portal.envs是这套 Portal 允许管理的环境列表dev、fat、uat、pro 用逗号分隔。apollo.portal.meta.servers是每个环境对应的 Meta Server 地址。这里我要重点展开说 Meta Server 和 Config Service 的区别Meta Server 是 Apollo 内部做服务发现用的一个逻辑地址它本身不提供配置读写能力但它会告诉你 Config Service 和 Admin Service 具体在哪个地址。对客户端来说只需要配置 Meta Server 地址客户端会自动发现 Config Service对 Portal 来说同样是通过apollo.portal.meta.servers去发现各环境的 Admin Service。在单环境、单机部署的情况下Meta Server 地址就是 Config Service 的地址填http://localhost:8080即可。如果后面接了多个环境apollo.portal.meta.servers要写成这样apollo.portal.envs dev,pro apollo.portal.meta.servers {dev:http://dev-config:8080,pro:http://pro-config:8080}这个 JSON 格式的映射关系到 Portal 能不能正确访问到各环境的服务写错一个 key 就会导致 Portal 里某个环境的项目列表打不开。4. 启动验证与失败排查从日志到 Eureka 页面的完整链路4.1 启动顺序不是绝对不能乱但稳妥顺序能省事先启动哪个其实 Apollo 的三个服务没有严格的启动顺序要求因为内置了 Eureka 之后服务之间是靠注册和定时拉取来互相发现的。不过实际部署中我习惯先启动 Config Service等它的日志里出现 Eureka 启动完成的标志后再启动 Admin Service最后启动 Portal。这样做的原因有两个第一Config Service 作为整个配置中心的读入口它启动后哪怕 Admin Service 还没起来客户端也不会大面积报错第二Portal 启动时如果发现不了 Admin Service虽然不会让进程退出但管理页面里的项目列表可能加载不出来给人一种启动失败的错觉。启动命令很简单cd /opt/apollo/configservice ./bin/startup.sh cd /opt/apollo/adminservice ./bin/startup.sh cd /opt/apollo/portal ./bin/startup.shstartup.sh内部其实调用了java -jar并把日志重定向到了 logs 目录下。启动后别急着看端口先看日志更靠谱。4.2 验证三件事端口、日志、Eureka 页面第一步验证端口是否在监听ss -tlnp | grep -E 8080|8090|8070正常情况下8080 是 Config Service8090 是 Admin Service8070 是 Portal。第二步是看启动日志有没有明显异常。每个服务目录下都有 logs 目录比如tail -f /opt/apollo/configservice/logs/apollo-configservice.log如果日志里出现类似Started ApolloConfigService in xx seconds的信息说明该服务启动成功了。如果一直卡在数据库连接或者 Eureka 注册阶段日志里通常会有异常堆栈这时候把关键异常信息复制到搜索引擎里查大多能找到原因。第三步是通过 Eureka 的健康检查接口确认服务实例是否注册成功。直接访问 Config Service 的 Eureka 页面http://服务器IP:8080/正常页面上应该能看到两个服务实例CONFIG-SERVICE 和 ADMIN-SERVICE。如果只看到 CONFIG-SERVICE说明 Admin Service 没注册上来去检查 Admin Service 的日志和两台服务之间的网络连通性。如果两个都看不到那基本可以断定 Eureka 配置有问题回到eureka.service.url去查。Portal 的验证方式是打开浏览器访问http://服务器IP:8070/默认登录账号是 apollo密码 admin。能进入管理页面说明 Portal 端到 Admin Service 再到数据库这条链路是通的。4.3 启动失败排查我把最常见的三类问题列出来第一类是端口被占用。Linux 上很多服务默认占用了 8080 或 8090比如某些监控组件、Java 应用服务器。查端口占用用lsof -i :8080或者ss -tlnp | grep 8080如果被占需要修改对应服务的server.port同时联动修改eureka.service.url里的端口和 Portal 里的 meta server 配置。这里三处联动最容易漏漏一处就会出现Portal 能打开但访问不了 Config Service的诡异问题。第二类是内存不足。在 2G 内存的服务器上部署不调 JVM 参数的话三个服务加上 MySQL 基本会 OOM。内存不足时日志里常见OutOfMemoryError或者服务启动后没过几分钟就自动退出。解决办法是调小所有服务的堆内存在startup.sh里或者环境变量里加上JAVA_OPTS比如export JAVA_OPTS-Xms512m -Xmx512mConfig Service 和 Admin Service 我一般给 512m 就够用Portal 因为是管理端界面256m 到 512m 也可以。单机部署时三个服务加 MySQL 控制在 2G 以内是可以跑起来的。第三类是数据库连不上。启动日志里如果出现CannotGetJdbcConnection或者Access denied优先检查数据库连接串里的 IP、用户名、密码以及 MySQL 的bind-address。注意 MySQL 8 默认的认证插件是caching_sha2_password而 Apollo 内置的数据库驱动版本如果太老连接时会报认证失败需要把数据库用户的认证插件改成mysql_native_passwordALTER USER apollo% IDENTIFIED WITH mysql_native_password BY YourStrongPassword;改完记得重启服务让连接池重新建立连接。4.4 用 systemd 托管告别手动启停手动跑startup.sh适合首次部署验证但生产环境里还是建议用 systemd 做进程托管。以 Config Service 为例在/etc/systemd/system/apollo-configservice.service里写[Unit] DescriptionApollo Config Service Afternetwork.target mysql.service [Service] Typesimple Userapollo WorkingDirectory/opt/apollo/configservice ExecStart/opt/apollo/configservice/scripts/startup.sh Restarton-failure RestartSec10 [Install] WantedBymulti-user.target但注意Apollo 自带的startup.sh里用nohup启动后命令会立即返回这和 systemd 的Typesimple配合得并不好。更合适的做法是直接调java -jar或者把startup.sh里的 Java 启动命令提取出来写进 systemd把Type设为simple这样 systemd 才能真正跟踪到进程状态服务挂掉后能自动拉起。三个服务都配置好之后systemctl daemon-reload systemctl enable apollo-configservice apollo-adminservice apollo-portal systemctl start apollo-configservice这样的托管方式省心很多服务器重启后服务能自动恢复不用手动去点。5. 部署完别急着接业务先做这几件事5.1 创建项目、Namespace理解发布这个动作服务都正常跑起来后第一件事不是急着写客户端代码而是在 Portal 里把项目结构建好。在 Portal 的首页点击创建项目填一个 AppId这个 AppId 将来就是客户端引用配置时的唯一标识。默认项目会带一个 application 的 Namespace可以往里加 Key-Value 格式的配置项。这里有一个非常重要的动作配置填好之后一定要点发布。Apollo 的配置不会在保存时生效必须先发布生成 Release 记录客户端才能拿到。很多第一次用 Apollo 的同事在 Portal 里改了配置以为保存就是生效结果客户端一直拿不到最新值折腾了半天发现只是没点发布。如果项目里需要区分环境比如同一个 AppId 在 dev 和 pro 里要有不同的数据库地址那就给不同环境分别配置即可。Apollo 的模型天然支持这种多环境隔离每个环境的配置独立保存、独立发布互不干扰。5.2 客户端接入的最小配置示例如果是 Spring Boot 项目接入 Apollo 其实很轻量。在application.properties里加# 指定 Apollo 的 AppId app.id SampleApp # 指定 Apollo Meta Server 地址 apollo.meta http://localhost:8080 # 开启 Apollo 配置 apollo.bootstrap.enabled true # 把 Namespace 注入 Spring 环境 apollo.bootstrap.namespaces application然后在 Maven 的pom.xml引入依赖dependency groupIdcom.ctrip.framework.apollo/groupId artifactIdapollo-client/artifactId version1.9.1/version /dependency启动应用后如果控制台出现 Apollo 拉取配置成功的日志说明整条链路已经通了客户端 - Config Service - ApolloConfigDB。接入时注意apollo.meta和app.id这两个配置一定不能少写错任何一个都会导致客户端连不上。5.3 账号安全与权限规划Apollo 的默认管理员账号是 apollo/admin这个账号能管理所有项目、所有环境。生产环境上第一步必须修改默认密码并且不要把 apollo 这个账号直接给开发人员日常使用。在 Portal 的权限管理里可以为每个项目分配负责人和开发者角色。开发者的权限是编辑配置、发布配置负责人则可以管理项目成员。Apollo 的权限模型粒度比较细支持精确到项目、环境、Namespace 级别的授权。部署完花点时间把权限规划好后面能省很多麻烦。这里我多说一句和运维相关的事Apollo 的数据库密码不要明文写在配置里散落到各个服务器上。我的做法是把密码统一放到环境变量里或者用专门的配置管理工具在启动时注入避免配置文件被误传或泄露。6. 个人踩坑清单这些坑光看文档发现不了最后分享几个我自己的实战经验。部署 Apollo 本身不复杂但有些坑不踩过一遍光看官方文档很难发现。第一个坑服务器上的 MySQL 是旧环境迁移过来的字符集是 latin1。Apollo 初始化脚本导入时看着没报错但中文配置发布后到了客户端变成问号。我的解决方式是重建数据库并明确指定 utf8mb4同时保证应用连接串里也带上characterEncodingutf8。第二个坑服务器上配置了 HTTP 代理环境变量http_proxy/https_proxy导致服务间通过 localhost 通信时被代理拦截Eureka 注册地址变成了一个奇怪的公网地址服务之间互相看不到。排查思路其实很直接先确认机器上有没有设置代理环境变量有的话在启动 Apollo 前清掉或者改成 no_proxy 里加 localhost。Eureka 页面上的服务实例地址如果是公网 IP 而不是内网 IP基本就是这个原因。第三个坑配置改完忘记发布。这个前面已经强调过了但还是要再说一次因为它的出现频率远超想象。Apollo 的配置发布走的是 Release 表只有发布过的版本才会生成对应的 Release 记录客户端只能拿到已发布的配置。如果你在 Portal 里改了配置客户端一直没变化先去页面上看一眼那条配置是不是处于未发布状态。第四个坑服务用 systemd 同时拉起结果 Config Service 和 Admin Service 启动过快Eureka 注册还没完成Portal 启动时发现不了 Admin Service管理页面能打开但项目列表一直是空的。后来改成顺序启动或者在 systemd 里配置Restarton-failure整个体验就顺了很多。第五个坑日志和临时目录的磁盘占用。Apollo 默认日志是滚动写的但如果服务长期不重启有些版本会产生大量 GC 日志和访问日志。建议统一给日志目录做 logrotate 或者定时清理特别是/opt/apollo下的 log 目录别等磁盘满了才发现。Apollo 这套东西部署起来确实有点繁琐但一旦跑顺了它在微服务配置管理上解决的是真痛点。希望这篇博文能帮你在 Linux 上把 Apollo 顺利跑起来少踩几个我当年踩过的坑。如果你在部署过程中遇到什么奇怪的问题多看看 logs 目录下的日志绝大多数答案都在里面。
返回列表