Docker安装Apollo

14 篇文章 0 订阅
1 篇文章 0 订阅

在这里插入图片描述
说明: apollo官网已经说明的很清楚 在这里记录仅为了记录 方便日后回顾

什么是Apollo

Apollo(阿波罗)是一款可靠的分布式配置管理中心,诞生于携程框架研发部,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

Apollo支持4个维度管理Key-Value格式的配置:

application (应用)
environment (环境)
cluster (集群)
namespace (命名空间)

同时,Apollo基于开源模式开发,开源地址:https://github.com/ctripcorp/apollo

Apollo的特点

  1. 统一管理不同环境,不同集群的配置
  2. 配置实时更新
  3. 版本发布
  4. 灰度发布
  5. 权限管理

Apollo的核心

  1. application 应用
  2. environment 环境
  3. cluster 集群
  4. namespace 命名空间

Apollo为什么采用Eureka

  1. Eureka是业界比较成熟的工具 并且是开源的 方便排查问题
  2. 由于携程本身主要使用Java的SpringCloud和Boot 所以和Eureka集成更方便

使用Docker安装Apollo

  • 安装Java jdk 1.8

  • 查找dockerhub中mysql镜像

    • docker search mysql
    • 在这里插入图片描述
  • 拉取docker的mysql镜像

    • docker pull mysql:5.7
  • 运行mysql镜像

    • docker run -d -p 13306:3306 --privileged=true -v /mnt/mysql/conf/mysql.conf:/etc/mysql/mysql.conf.d/mysqld.cnf -v /mnt/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    • run run 是运行一个容器
      -d  表示后台运行
      -p  表示容器内部端口和服务器端口映射关联
      –privileged=true 设值MySQL 的root用户权限, 否则外部不能使用root用户登陆
      -v /docker/mysql/conf/my.cnf:/etc/my.cnf 将服务器中的my.cnf配置映射到docker中的/docker/mysql/conf/my.cnf配置
      -v /docker/mysql/data:/var/lib/mysql  同上,映射数据库的数据目录, 避免以后docker删除重新运行MySQL容器时数据丢失
      -e MYSQL_ROOT_PASSWORD=123456   设置MySQL数据库root用户的密码
      –name mysql     设值容器名称为mysql
      mysql:5.7  表示从docker镜像mysql:5.7中启动一个容器
      –character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci 设值数据库默认编码

    • 在这里插入图片描述
    • 在这里插入图片描述
  • 进入mysql容器

    • docker exec -it 1de812984103 bash
    • 1de812984103 容器id
      exec 在运行的容器中执行命令
      -it 以交互模式执行
      bash 脚本类型

    • 在这里插入图片描述
  • 连接mysql

    • mysql -u root -p

    • 在这里插入图片描述

    • 在这里我们直接使用连接时指定的密码进行登录即可 后面如果要更改密码 可参考mysql命令文档进行操作

  • 导入apollo系统数据

  • 下载apollo服务镜像

    • dockerhub地址
    • docker pull apolloconfig/apollo-portal:latest
      docker pull apolloconfig/apollo-adminservice:latest
      docker pull apolloconfig/apollo-configservice:latest

    • apollo-adminservice //Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
      apollo-configservice //Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端
      apollo-portal //Portal通过域名访问Meta Server获取Admin Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Portal侧会做load balance、错误重试

  • 运行镜像

    • 在这里为了避免和其他服务端口冲突 所以使用8081 8091 8071来对应容器端口

    • Apollo Config Service

      • docker run -p 8081:8080 \ -e SPRING_DATASOURCE_URL="jdbc:mysql://localhost:13306/ApolloConfigDB?characterEncoding=utf8" \ -e SPRING_DATASOURCE_USERNAME=root -e SPRING_DATASOURCE_PASSWORD=123456 \ -d -v /tmp/logs:/opt/logs --name apollo-configservice apolloconfig/apollo-configservice
    • Apollo Admin Service

      • docker run -p 8091:8090 \ -e SPRING_DATASOURCE_URL="jdbc:mysql://localhost:13306/ApolloConfigDB?characterEncoding=utf8" \ -e SPRING_DATASOURCE_USERNAME=root -e SPRING_DATASOURCE_PASSWORD=123456 \ -d -v /tmp/logs:/opt/logs --name apollo-adminservice apolloconfig/apollo-adminservice
    • Apollo Portal

      • docker run -p 8071:8070 \ -e SPRING_DATASOURCE_URL="jdbc:mysql://localhost:13306/ApolloPortalDB?characterEncoding=utf8" \ -e SPRING_DATASOURCE_USERNAME=root -e SPRING_DATASOURCE_PASSWORD=123456 \ -e APOLLO_PORTAL_ENVS=pro \ -e PRO_META=http://localhost:8081 \ -d -v /tmp/logs:/opt/logs --name apollo-portal apolloconfig/apollo-portal
    • 参数说明

      • SPRING_DATASOURCE_URL: 对应环境ApolloConfigDB的地址
        SPRING_DATASOURCE_USERNAME: 对应环境ApolloConfigDB的用户名
        SPRING_DATASOURCE_PASSWORD: 对应环境ApolloConfigDB的密码
        APOLLO_PORTAL_ENVS(可选): 对应ApolloPortalDB中的apollo.portal.envs配置项,如果没有在数据库中配置的话,可以通过此环境参数配置
        DEV_META/PRO_META(可选): 配置对应环境的Meta Service地址,以${ENV}_META命名,需要注意的是如果配置了ApolloPortalDB中的apollo.portal.meta.servers配置,则以apollo.portal.meta.servers中的配置为准

  • 运行结果

    • 在这里插入图片描述
  • 访问

    • 在这里插入图片描述
  • apollo登录默认用户名和密码 apollo admin

    • 在这里插入图片描述
  • 添加用户

    • 在这里插入图片描述
  • 添加部门

    • 在这里插入图片描述
    • key: organizations
      value: [{“orgId”:“测试部门”,“orgName”:“测试部门”}]

NodeJs对接Apollo

NestJs

Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的开发框架。它利用 JavaScript 的渐进增强的能力,使用并完全支持 TypeScript (仍然允许开发者使用纯 JavaScript 进行开发),并结合了 OOP (面向对象编程)、FP (函数式编程)和 FRP (函数响应式编程)。

ctrip-apollo

用于支持nodejs对接apollo的插件

npm i ctrip-apollo
Dockerfile

使用docker容器进行构建并启动的执行脚本

# 获取node镜像
FROM node:12

# 创建工作目录
RUN mkdir app

# 设置工作目录
WORKDIR /app

# 拷贝目录
COPY . /app

# 镜像的维护者
MAINTAINER zhangzw

# 安装npm包
RUN npm --registry https://registry.npm.taobao.org i

# 安装全局pm2
RUN npm --registry https://registry.npm.taobao.org i -g pm2

# 编译
RUN npm run build

# 容器端口
EXPOSE 3000

RUN mkdir -p /usr/share/zoneinfo/Asia/

RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo 'Asia/Shanghai' >/etc/timezone

RUN dpkg-reconfigure -f noninteractive tzdata

# 配置环境变量
ENV NODE_ENV production

# 设置时区
ENV TZ "Asia/Shanghai"

# 启动命令
CMD ["pm2-runtime", "start", "dist/src/main.js", "-i", "2"]

.production.env

用于区分环境 在nestjs启动时 绑定环境变量

APOLLO_CLUSTER=v-test
APOLLO_HOST=http://localhost:8081
APOLLO_APP_ID=server
APOLLO_NAMESPACES=application,config
APP_ID=nestjs
APP_PORT=3000
NODE_ENV=production
AppEnvModule

使用nestjs配置模块绑定全局env变量
NODE_ENV是在启动时指定的 由于我本地使用的是docker 所以在启动是NODE_ENV的值就是production了

import { Global, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

const NODE_ENV = process.env.NODE_ENV;

@Global()
@Module({
  imports: [
    ConfigModule.forRoot(
      {
        envFilePath: NODE_ENV === 'production' ? '.production.env' : '.dev.env',
        isGlobal: true,
      }
    ),
  ],
})
export class AppEnvModule { }

apollo.service.ts

用于初始化apollo连接和获取配置函数
@Injectable({ scope: Scope.DEFAULT }) // 该实例多个类之间可进行共享
lock // 避免重复初始化配置的标记
Log // 封装好的日志组件 内部使用的是log4js

import { Injectable, Scope } from '@nestjs/common';
import * as apollo from 'ctrip-apollo';
import { Log } from 'src/log';
import * as bluebird from 'bluebird';
import { IApolloVariable } from './apollo.interface';

@Injectable({ scope: Scope.DEFAULT })
export class ApolloService {

  private apolloVariable: IApolloVariable;
  private apolloClient: any;
  private lock = false;

  constructor(
    private readonly log: Log,
  ) {
    this.log.setContext(ApolloService.name);
  }

  // 获取apollo配置
  public async getApolloVariable (): Promise<IApolloVariable> {
    if (this.apolloVariable) {
      return this.apolloVariable;
    }
    // 解决异步获取配置后 但没有及时返回造成的重复获取问题
    if (this.lock) {
      this.apolloVariable = await this.waitGetRealApolloVariable();
      return this.apolloVariable;
    }
    this.apolloVariable = await this.getRealApolloVariable();
    return this.apolloVariable;
  }

  // 获取远程apollo配置
  private async getRealApolloVariable (): Promise<IApolloVariable> {
    this.lock = true;
    let variable: any = {};
    const { APOLLO_HOST, APOLLO_CLUSTER, APOLLO_NAMESPACES, APOLLO_APP_ID } = process.env;
    this.apolloClient = apollo({ host: APOLLO_HOST, appId: APOLLO_APP_ID, cluster: APOLLO_CLUSTER });
    try {
      await bluebird.Promise.map(APOLLO_NAMESPACES.split(','), async (nsName) => {
        const ns = this.apolloClient.namespace(nsName);
        let conf = await ns.ready();
        conf = conf.config();
        this.log.info(`${nsName} 配置:${JSON.stringify(conf)}`);
        for (const k of Object.keys(conf)) {
          if (variable[k]) {
            throw new Error('apollo配置重复:' + k);
          }
        }
        variable = { ...variable, ...conf };
        this.listenNs(ns, nsName);
      });
    } catch (error) {
      this.log.error('获取apollo配置出错,退出.', error);
      process.exit(1);
    }
    return variable;
  }

  // 等待获取配置
  private async waitGetRealApolloVariable (): Promise<IApolloVariable> {
    return new Promise(async (resolve) => {
      const timer = setInterval(async () => {
        try {
          this.log.info('apollo 等待获取配置中', this.apolloVariable);
          if (this.apolloVariable) {
            clearInterval(timer);
            return resolve(this.apolloVariable);
          }
        } catch (error) {
          this.log.error(`apollo 等待获取配置异常 ${error}`);
        }
      }, 100);
    });
  }

  // 监听配置变更并实时更新
  private listenNs (ns, nsName) {
    ns.on('change', ({ key, oldValue, newValue }) => {
      this.log.info(
        `apollo配置变更: ns【${nsName}】key【${key}】从【${oldValue}】变为【${newValue}`,
      );
      this.apolloVariable[key] = newValue;
    });

    ns.on('add', ({ key, value }) => {
      this.log.info(
        `apollo配置新增: ns【${nsName}】key【${key}】值【${value}`,
      );
      if (this.apolloVariable[key]) {
        this.log.error(`新增失败,配置重复 ${key}`, '');
        return;
      }
      this.apolloVariable[key] = value;
    });

    // do nothing
    ns.on('delete', ({ key, value }) => {
      this.log.info(
        `apollo配置删除: ns【${nsName}】key【${key}】值【${value}`,
      );
    });
  }

}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值