背景

由于公司sonar需要升级,但是又不想用收费版。所以需要基于社区版改造。原来社区版只支持all in one。这样的话对于生产环境其实是不可取的,稳定性得不到保障,所以需要对其改造。

源代码获取

首先,先把github代码拉到本地。Github地址

切换到最新的打包分支

git checkout 25.7.0.110598

代码改造

首先 社区版是支持配置数据库的,但是对于ES,在启动的时候会启动ES客户端,所以我们需要把这块干掉。不启动自带客户端,然后连接远程的ES即可。


public class SchedulerImpl implements Scheduler, ManagedProcessEventListener, ProcessLifecycleListener, AppStateListener {
 

  private void tryToStartAll() throws InterruptedException {
      //不启动自带ES
      //tryToStartEs();
      tryToStartWeb();
      tryToStartCe();
  }
  
  private void tryToStartWeb() throws InterruptedException {
      ManagedProcessHandler process = processesById.get(ProcessId.WEB_SERVER);
      if (process == null) {
          return;
      }
      //不检查ES
  //    if (!isEsOperational()) {
  //      if (firstWaitingEsLog.getAndSet(false)) {
  //        LOG.info("Waiting for Elasticsearch to be up and running");
  //      }
  //      return;
  //    }
      if (appState.tryToLockWebLeader()) {
          tryToStartWebLeader(process);
      } else if (appState.isOperational(ProcessId.WEB_SERVER, false)) {
          tryToStartProcess(process, () -> commandFactory.createWebCommand(false));
      } else {
          Optional<String> leader = appState.getLeaderHostName();
          if (leader.isPresent()) {
              LOG.info("Waiting for initialization from {}", leader.get());
          } else {
              LOG.error("Initialization failed. All nodes must be restarted");
          }
      }
  }
  
  private void stopAll() throws InterruptedException {
      // order is important for non-cluster mode
      LOG.info("Sonarqube has been requested to stop");
      stopProcess(ProcessId.COMPUTE_ENGINE);
      stopProcess(ProcessId.WEB_SERVER);
      //stopProcess(ProcessId.ELASTICSEARCH);
  }
}

其次,你需要让Sonar连接你配置的远程ES

public class EsClientProvider {

    @Bean("EsClient")
    public EsClient provide(Configuration config) {
        Settings.Builder esSettings = Settings.builder();

        // mandatory property defined by bootstrap process
        esSettings.put("cluster.name", config.get(CLUSTER_NAME.getKey()).get());

        boolean clusterEnabled = config.getBoolean(CLUSTER_ENABLED.getKey()).orElse(false);
        boolean searchNode = !clusterEnabled || SEARCH.equals(NodeType.parse(config.get(CLUSTER_NODE_TYPE.getKey()).orElse(null)));
        List<HttpHost> httpHosts;
        // 主要改动点,就是如果是配置了CLUSTER_SEARCH_HOSTS 就直接连远程ES  这样就可以了。
        if ((clusterEnabled && !searchNode) || config.get(CLUSTER_SEARCH_HOSTS.getKey()).isPresent()) {
            httpHosts = getHttpHosts(config);

            LOGGER.atInfo()
                    .addArgument(() -> displayedAddresses(httpHosts))
                    .log("Connected to remote Elasticsearch: [{}]");
        } else {
            // defaults provided in:
            // * in org.sonar.process.ProcessProperties.Property.SEARCH_HOST
            // * in org.sonar.process.ProcessProperties.Property.SEARCH_PORT
            HostAndPort host = HostAndPort.fromParts(config.get(SEARCH_HOST.getKey()).get(), config.getInt(SEARCH_PORT.getKey()).get());
            httpHosts = Collections.singletonList(toHttpHost(host, config));
            LOGGER.atInfo()
                    .addArgument(() -> displayedAddresses(httpHosts))
                    .log("Connected to local Elasticsearch: [{}]");
        }

        return new EsClient(config.get(CLUSTER_SEARCH_PASSWORD.getKey()).orElse(null),
                config.get(CLUSTER_ES_HTTP_KEYSTORE.getKey()).orElse(null),
                config.get

方案

由nginx通过请求特征分析打到哪个服务。ES部署三台,pg做主从同步。