Skip to main content

4 posts tagged with "Practice"

View All Tags

· 7 min read
Panda

一、简介​

Docusaurus 是一款静态网站生成器,可以帮助我们快速搭建一个优美的文档网站。

Docusaurus 的基本特性主要有:

  • 支持 Markdown
  • 支持侧边栏
  • 支持目录导航
  • 支持提示功能
  • 支持自定义样式
  • ……

此外,Docusaurus 还有一些高级特性:

  • 支持夜间模式
  • 支持站内搜索
  • 支持 SEO 优化
  • 支持插件扩展
  • 支持多语言
  • 支持多版本
  • ……

以下为 Docusaurus 的官网截图,我们可以先一睹为快:

二、核心组件​

Docusaurus 的核心组件有:Docs、Blog、Pages。

2.1 Docs​

Docs 为用户提供了按层级管理 Markdown 文档的功能,由官方插件 @docusaurus/plugin-content-docs 提供支持。

在 Docs 中,Markdown 文档具有清晰的层级关系,如下图所示:

2.2 Blog​

Blog 即为我们熟知的博客。

该功能由官方插件 @docusaurus/plugin-content-blog 提供,可以帮助我们快速搭建博客页面。

下图为 Blog 示例:

2.3 Pages​

Pages 指独立的页面,页面之间没有父子关系,由官方插件 @docusaurus/plugin-content-pages 提供支持。

在 Docusaurus 中,用户可以添加一个 React 页面,也可以添加一个 Markdown 页面。

下图为 Pages 示例:

三、使用指南​

3.1 环境准备​

Docusaurus 要求我们预先安装以下组件:

caution

yarn 指的是依赖管理工具,并不是 Hadoop 中的资源管理器 yarn。若本地安装了 Hadoop,注意在环境变量中去掉 yarn 脚本的地址,避免 yarn 命令冲突。

3.2 创建站点​

在任意路径执行以下命令:

npx create-docusaurus@latest my-website classic

若创建成功,在当前路径下会出现 my-website 目录,且控制台输出如下信息:

3.3 配置说明​

my-website 目录下包含多个配置文件,这些配置文件的具体作用可参考下表:

配置文件具体说明
docusaurus.config.js核心配置文件,包含基础信息配置、插件配置、主题配置等
src/css/custom.css自定义样式设置
src/pages/index.js主页标题栏配置
src/components/HomepageFeatures.js主页特性栏配置
info

具体配置项说明请参考官方文档:https://docusaurus.io/docs/api/docusaurus-config。

3.4 快速启动​

进入 my-website 目录,输入以下命令快速启动站点:

npx docusaurus start

若启动正常,则控制台会输出如下信息:

此时,我们便可以通过 http://localhost:3000/ 预览我们的本地站点。

3.5 语法高亮​

默认情况下,Docusaurus 未开启 Java、Scala 等语言的语法高亮,需要我们在 docusaurus.config.js 增加如下配置:

module.exports = {
// ...
themeConfig: {
prism: {
additionalLanguages: ['powershell'],
},
// ...
},
};
info

Docusaurus 基于 Prism 实现语法高亮。

四、编辑器​

4.1 编辑器选择​

对于自建博客来说,找到合适的 MD 编辑器是非常重要的一件事,这将会影响到我们的文档编写体验与发布效率。

若条件允许,我们希望编辑器可以满足以下功能:

  • 功能一:支持与博客站点相同的文档层级结构
  • 功能二:支持自定义 CSS,以实现本地的实时预览
  • 功能三:支持与站点相同的提示功能与语法(Admonition),以实现本地的实时预览
  • 功能四:支持源文件快速同步

基于这些功能需求,笔者类比了几款知名 MD 编辑器,得出如下结论:

编辑器功能一功能二功能三功能四
Mark Text✅❌❌❌
Joplin❌✅✅✅
Obsidian✅✅✅❌
info

Typero 目前已收费,因此不列入比较清单。此外,Obsidian 实际上是支持功能四的,但是需要付费。

综合以上,笔者最终选择 Obsidian 作为本地的编辑器,其编辑界面如下图所示:

4.2 自定义设置​

使用 Obsidian,我们有两个自定义项需要设置。

4.2.1 自定义 CSS​

自定义 CSS 可以帮助我们复制博客站点的 CSS,使编辑器的预览样式与站点一致。为实现该功能,需要以下步骤:

  1. 在 .obsidian/snippets 目录下创建 custom.css 文件,将博客站点的全部 CSS 复制到该文件中
  2. 通过路径 Settings → Appearance → CSS snippets 进入设置页面,点击按钮启用自定义样式

4.2.2 Admonition​

默认情况下,Obsidian 不支持 Admonition。

为了使 Obsidian 支持 Admonition,我们需要下载 Admonition 插件,然后安装到目录 .obsidian/plugins。

info

Admonition 的下载地址为:https://github.com/valentine195/obsidian-admonition。

安装完成后,进入设置页面,并启用 Enable Non-codeblock Admonitions:

插件支持的提示语法为 !!! 或 ???,与博客站点的 ::: 不同,因此我们还需要做一些修改。

打开目录 .obsidian/plugins/obsidian-admonition 下的 main.js 文件,找到其中的 enableMarkdownProcessor 方法,将 TYPE_REGEX 和 END_REGEX 修改为图中所示值:

重启 Obsidian,此时,我们便可以正常使用 Admonition 功能了。

五、部署​

我们已经完成了 Docusaurus 的本地启动和编辑,现在,我们还需要将它发布到 GitHub Pages。

发布时,只需在 my-website 目录下输入以下命令:

set "GIT_USER=xxx" && set "GIT_PASS=xxx" && yarn deploy

其中,各参数的说明为:

  • GIT_USER:用户的 GitHub 账号
  • GIT_PASS:用户的 GitHub 私有凭证
caution

GIT_PASS 并非指密码,而是私有凭证,其生成方式请参考:https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token。

· 5 min read
Panda

一、前言​

与 Java 不同,Scala 比较小众,没有放之四海而皆准的规范。

为了使团队在 Scala 项目上的代码尽可能地保持一致,笔者在借鉴 官方文档、开源项目 的基础上,整理了适用于自身团队的 Scala 代码规范。

二、项目创建规约​

本规约展示了一个在 IDEA 上创建 Scala 项目的流程,以供参考。

2.1 依赖管理​

Scala 支持通过 Maven 或 sbt 来管理项目。基于以下因素,我们选择 Maven:

  • Scala 开源项目大部分都是通过 Maven 进行管理
  • 团队成员对 Maven 比较熟悉,学习成本低
  • 主流持续集成产品对 Maven 支持度比较高

使用 Maven 创建 Scala 项目时,与 Java 无太大区别,可以通过 archetype 快速创建:

此时,项目仅能创建 Java 类,还无法创建 Scala 类。

2.2 Scala SDK​

Scala SDK 是 Scala 项目中不可缺少的部分,我们可以在 Project Structure 完成 Scala SDK 的添加。

info

若本地没有 Scala SDK,可以点击 + 号,在弹出的对话框中选择对应的 Scala 版本进行下载。

2.3 框架支持​

此时,距离完整创建 Scala 项目还差最后一步,即框架支持。

我们可以右键项目根目录,点击 Add Framework Support,然后会弹出如下对话框:

勾选 Scala,点击 OK。此时,Scala 项目创建完毕,可以在项目中新建 Scala 类并进行编码。

三、代码风格规约​

Scala 官方提供了代码风格参考:

https://docs.scala-lang.org/style/index.html

但是,基于文档的规约常常是不安全的,团队中总会有“糊涂蛋”一不小心犯了“错”。为避免这个问题,我们可以引入 Scalafmt 插件,以强制的手段保证项目代码风格的一致性。

3.1 Scalafmt 安装​

Scalafmt 可以直接在 IDEA 的插件商场中安装。

安装完成后,需重启 IDEA。

3.2 Scalafmt 配置​

Scalafmt 基于 .scalafmt.conf 文件实现配置。

首先,打开 Settings,进入 Editor > Code Style > Scala 界面,将 Formatter 设置为 Scalafmt,如下图所示:

然后,在项目根目录下创建 .scalafmt.conf 文件,输入如下内容:

maxColumn = 150

若配置成功,可在 Editor > Code Style > Scala 界面看到如下结果:

3.3 变量类型补全​

在 Scala 中,变量的实际类型可以是不显式指定的。例如,我们可以这样定义字符串类型的变量:

val value = "panda"

实际上,它的完整表达式是:

val value: String = "panda"

为了提高代码阅读性,使其他开发人员能快速知晓变量的实际类型,我们规定 变量类型要完全补全。

在 Java 开发中,我们常常使用 .var 实现变量类型自动补全。但是,在 Scala 项目里,.var 补全的内容默认情况下是不显示实际类型的,如下图所示:

若想要显示实际类型,需要在 Type Annotations 选项卡中勾选 Local definition 选项,并取消勾选 Type is stable* 选项:

此时,再次使用 .var 进行补全时,会发现变量的实际类型已经自动补上了。

· 11 min read
Panda

一、为什么要用 Jenkins?​

目前,我们在持续集成上使用的是 GitLab 自带的 gitlab-ci。它支持自动化完成代码编译、镜像构建与镜像推送,减少开发人员在项目构建上的时间开销。

但是,gitlab-ci 有一个明显的缺陷:在遇到多模块项目时(如基于 SpringBoot 搭建的微服务项目),它显得有些无力。具体表现为,gitlab-ci 不支持多管道,每当项目中某个模块的代码有新的提交,gitlab-ci 都会触发全项目的自动构建,而无法仅针对产生变动的子模块进行构建。当项目规模较大时,这种构建方式会导致自动构建的代价非常大。

而在这种场景下,Jenkins 可以很好地实现我们的需求。当代码提交触发构建事件时,Jenkins 可以筛选出产生变动的子模块,并对这些子模块进行构建与打包,使我们的自动化构建变得精准而优雅。

下图为 Jenkins 持续集成的工作流示意图:

二、Jenkins 安装与部署​

本节将介绍 Jenkins 的安装与部署。若只想了解流水线的构建,可以直接跳过本节内容。

2.1 环境准备​

我们将采用 Docker 的方式部署 Jenkins,因此,部署前需在宿主机完成 Docker 环境的搭建。

info

Docker 环境搭建不作为本文分享内容,请自行实现。

2.2 基础镜像​

Jenkins 官方已提供现成的 Docker 镜像 jenkinsci/blueocean,该镜像内已包含以下组件:

  • Docker
  • Java
  • Git

但是我们不能直接使用它,因为它并未安装常用的构建工具(如 Maven、Gradle 等)。

为解决这个问题,我们可以参考以下 Dockerfile 文件,构建符合我们自身需求的 Jenkins 镜像:

FROM jenkinsci/blueocean:1.24.7
MAINTAINER pentaxie@qq.com

ARG BASE_DIR=/opt/maven

USER root
ADD apache-maven-3.6.3-bin.tar.gz ${BASE_DIR}
ADD settings.xml ${BASE_DIR}/apache-maven-3.6.3/conf
RUN ["cp","/usr/share/zoneinfo/Asia/Shanghai","/etc/localtime"]

ENV M2_HOME=${BASE_DIR}/apache-maven-3.6.3
ENV PATH=$PATH:$M2_HOME/bin
info

该镜像在官方镜像的基础上,安装了 Maven,并相应地修改了 Maven 配置文件。

2.3 启动 Jenkins​

完成 Jenkins 基础镜像的构建后,我们可以直接使用 Docker 命令启动容器:

docker run \
-u root \
-d \
-p 38080:8080 \
-v /data/test/jenkins-data:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
hub.panda.com/dc-jenkins:2.289

其中,两个 -v 需要了解其作用:

  • 第一个 -v 表示将 Jenkins 的安装及数据存储目录挂载到宿主机,下次我们重启 Jenkins 的 Docker 容器时,Jenkins 中的数据才得以保留
  • 第二个 -v 表示支持容器内的 Docker 客户端直接使用宿主机的 Docker 服务,这样我们在容器内执行构建命令时,实际上是在宿主机构建镜像

2.4 插件安装​

Jenkins 启动后,首先需要安装社区推荐的插件。

除此之外,我们还需要在 插件管理 界面自行安装以下插件:

  • GitLab
  • Maven Integration
  • Pathignore

上述插件的主要功能为:

插件名称主要功能
GitLab支持 GitLab Token 的配置
Maven IntegrationMaven 集成插件,支持在流水线中创建 Maven Project
Pathignore路径过滤插件,支持子模块过滤(实现多模块持续集成的关键)

2.5 必要配置​

2.5.1 GitLab Token 设置​

安装完 GitLab 插件后,需要在 系统管理 - 系统设置 页面添加 GitLab Token。

GitLab Token 是 GitLab 提供的身份验证的令牌,其生成方式可参考下图:

info

该 Token 尽可能赋予足够的权限,避免后续 Jenkins 集成出现权限不足的情况。

info

添加后,需点击图中的 Test Connection 按钮进行校验,确保 Token 可以正常运作。

2.5.2 Maven 设置​

基础镜像部分介绍到,我们在官方 Jenkins 镜像的基础上安装了 Maven,并设置了环境变量与配置文件。

但这些还不够,使用 Jenkins 时,我们还需要在 系统管理 - 全局工具配置 页面中配置 Maven 的具体位置,使 Jenkins 能准确找到 Maven 的地址。

2.5.3 时区设置​

在基础镜像部分,我们已经将镜像的时区设置为东八区。

但是在 Jenkins 的界面中,每个用户的初始时区都是伦敦时间,需要我们手动设置为东八区:

完成此步骤后,Jenkins 的整个初始化配置过程便完成了,接下来可开始创建流水线进行深入体验。

三、构建流水线​

本节将以 多模块集成流水线 为例,展示具体的流水线构建流程。

3.1 创建任务​

集成了 Maven Integration 插件后,我们就可以在 新建任务 界面中创建一个 Maven Project:

info

通过 Maven Project,我们可以很便捷地在 Jenkins 上实现代码的编译与打包。

3.2 配置流水线​

流水线任务创建后,需要经过一系列配置。

3.2.1 代码源​

Jenkins 支持从 GitLab 上拉取代码。

caution

仓库地址记得使用 HTTPS,如果要使用 SSH 方式,需在容器中创建私钥(本文不介绍此种方式)。

如果我们的 GitLab 项目是 Private 级别,那么我们还需要创建一个 GitLab 凭据(Username with password),该凭据需要填写具有项目对应权限的 GitLab 用户名与密码,如下所示:

3.2.2 构建器​

构建器用于设置流水线任务触发的条件。

在本例中,我们勾选 Build when a change is pushed to GitLab。

该选项实现了当 GitLab 上有代码提交等行为时,触发 Jenkins 作业。

需要注意的是,要实现 GitLab 主动向 Jenkins 推送触发事件,需在 GitLab 上配置 Webhooks:

Webhooks 中,有两个配置项需要格外注意:

  • URL 为 Jenkins 对应构建项目的地址,如本例为:http://192.168.5.98:38080/project/demo
  • Secret token 为 Jenkins 对应构建项目的令牌,通过点击 高级 按钮进行生成,具体示例可见下图

此外,图例中的 Allowed Branched 需要指定触发构建的分支。默认情况下,任意分支的提交都会触发构建任务。

info

在本例中,我们设置为只有 master 分支发生变更才会触发构建任务。

3.2.3 构建环境​

构建环境设定了构建过程中的一些条件与行为。

由于本节主要介绍多模块的持续集成,因此关键点在于 Do not build if only specified paths have changed 选项。

info

该选项由 Pathignore 插件提供,可支持子模块的单独构建。

图例中的配置表示,只有子模块 dim-service 产生了变更项,才会触发构建任务。这是实现多模块持续集成的根基,在此基础上,我们可以很轻松地过滤掉其他子模块的构建流程。

3.2.4 Pre Steps​

顾名思义,Pre Steps 可以完成构建前的一些准备工作。

例如,我们想要在构建时推送 Docker 镜像,那么就需要提前登录对应的 Docker 仓库:

3.2.5 Build​

该步骤指明了我们整个流水线想要完成的构建指令。

在本例中,我们通过 -pl 参数指定构建的模块为 dim-service,配合上述 Pathignore 插件的过滤功能,我们可以实现当 dim-serivce 子模块发生变更项时自动触发该模块的 Docker 镜像创建与推送:

info

docker:build 与 docker:push 依赖 docker-maven-plugin 插件,可自行研究,或等待后续教程。

完成上述所有步骤后,点击 应用 与 保存,便完成了流水线的配置。如果项目有多个模块,创建多个对应的流水线任务即可。

3.3 构建与验收​

现在,我们可以提交一次代码,验证一下流水线任务执行情况。若无异常,在我们提交代码后,流水线会自动开启构建任务,完成我们预设的构建工作。

info

代码提交时,各子模块对应的流水线任务都会被触发,但是由于 Pathignore 插件的作用,流水线任务检测自身对应的子模块无变更项时,当前被触发的构建任务不会执行任何构建操作。

在构建任务明细中,可以通过点击 控制台输出 按钮,查看具体的构建日志:

如果一切顺利,即可在我们的 Docker 私仓里看到本次构建的镜像了!

· 16 min read
Panda

一、背景介绍​

目前,成熟的代码检测工具有很多,如 SpotBugs(前身为 FindBugs)、PMD、Checkstyle 等,我们可以在本地开发环境,非常便捷地利用这些工具实现代码的扫描与检测。这看上去好像很不错,但实际上,采用这种代码检测方式,我们面临着两个问题:

  • 代码提交前需要手动运行检测工具
  • 检测结果仅对自己可见

那么,有没有什么方案可以规避这些问题呢?答案当然是有的。

我们可以基于 GitLab 和 SonarQube 搭建自动化代码检测平台,并通过该平台实现以下功能:

  • 每次提交时,自动触发 SonarQube 代码检测,产生检测报告(包含坏味道、BUG 数、覆盖率等)
  • 上述检测报告,若来源于主分支提交或合并,则发送至 SonarQube,若来源于其他分支提交,则以评论形式直接反馈至 GitLab
info

如果不知道 SonarQube 是什么,可以参考 SonarQube 官方网站。

二、环境要求​

本次搭建使用的操作系统为 CentOS 7,需要安装的组件如下表所示:

组件名版本号
SonarQube6.7
GitLab11.1.4
GitLab-Runner13.0.1
Maven3.6.3

实际版本号需严格遵循表格中的版本号,避免出现兼容性问题。目前,笔者已知的兼容性问题有以下几点:

  • SonarQube 在 7.6 版本后不支持插件 sonar-gitlab-plugin,若使用 7.6 之后的版本,将无法实现 SonarQube 与 GitLab 协作(除非使用付费版)
  • GitLab 与 GitLab-Runner 的版本要考虑兼容性,否则会出现 GitLab-Runner 无法连接至 GitLab 的问题

三、安装与配置​

本节将描述上述组件安装与配置的详细步骤。其中,安装方式主要有本地安装和基于 Docker 安装,因此在安装前需确保宿主机已经具备 Docker 和 Docker Compose 的环境。

3.1 SonarQube​

3.1.1 SonarQube 安装​

使用 Docker Compose 安装 SonarQube 很简单,只需以下几个步骤:

  • 在任意位置创建安装目录 sonar,如 /usr/local/sonar
  • 在安装目录下创建 docker-compose.yml 文件,文件内容如下:
version: '2.1'

services:
# 使用 PostgreSQL 作为 SonarQube 的持久化方案
# 注:由于 SonarQube 7.9 及之后的版本不支持 MySQL,因此 MySQL 不作为考虑对象
postgres:
image: postgres:12
container_name: sonarqube_postgres
privileged: true
ports:
- "5432:5432"
networks:
- sonarnet
restart: always
# 将 PostgreSQL 数据文件存放至宿主机
volumes:
- ./postgres:/var/lib/postgresql/data
environment:
POSTGRES_DB: sonar
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar

sonarqube:
image: sonarqube:6.7
container_name: sonarqube
privileged: true
ports:
- "9000:9000"
restart: always
networks:
- sonarnet
depends_on:
- postgres
# 将 SonarQube 日志文件、数据文件、配置文件、扩展插件存放至宿主机
volumes:
- ./data:/opt/sonarqube/data
- ./extensions:/opt/sonarqube/extensions
- ./logs:/opt/sonarqube/logs
- ./conf:/opt/sonarqube/conf
# 配置 SonarQube 的数据源,本例为 PostgreSQL
environment:
SONARQUBE_JDBC_USERNAME: sonar
SONARQUBE_JDBC_PASSWORD: sonar
SONARQUBE_JDBC_URL: jdbc:postgresql://postgres:5432/sonar?useUnicode=true&characterEncoding=utf8
# 由于 SonarQube 内部会启动 ElasticSearch,因此需要此配置
ulimits:
nproc: 65535
nofile:
soft: 65536
hard: 65536

networks:
sonarnet:
driver: bridge
  • 在安装目录下分别创建 data、extensions、logs、conf 文件夹,并使用 chmod -R 777 <dir> 赋予所有权限,避免出现权限问题
  • 若宿主机有开启防护墙,需开放上述配置的端口:
firewall-cmd --add-port=5432/tcp --permanent
firewall-cmd --add-port=9000/tcp --permanent
firewall-cmd --reload
  • 在安装目录下,使用 docker-compose up -d 命令启动 SonarQube,若启动成功,控制台输出如下日志:
Creating network "sonar_sonarnet" with driver "bridge"
Creating sonarqube_postgres ... done
Creating sonarqube ... done
  • 打开浏览器,输入地址 http://sonar.example.com:9000 访问 SonarQube,若访问成功,则出现如下页面:

info

安装完成后,SonarQube 会自动生成管理员账号 admin:admin。

3.1.2 SonarQube 插件​

SonarQube 安装完成后,还需要安装部分插件以支持某些功能,具体插件清单如下:

插件名版本号插件用途
sonar-gitlab-plugin3.0.2为每个 GitLab 提交提供代码注释和评论的功能
sonar-l10n-zh-plugin1.19支持 SonarQube 汉化

插件安装非常简单,只需要将插件 jar 包放至扩展目录 ${sonarqube_home}/extensions/plugins 下,重启 SonarQube 即可。

关于 SonarQube 与 sonar-gitlab-plugin 的版本对照,可以参考:

https://github.com/gabrie-allaigre/sonar-gitlab-plugin

关于 SonarQube 与 sonar-l10n-zh-plugin 的版本对照,可以参考:

https://github.com/SonarQubeCommunity/sonar-l10n-zh%20

info

上述插件不支持在 SonarQube 的应用中心直接下载,因为官方已经不再提供这两款插件的在线安装了,我们可以直接在上述的 GitHub 地址中下载指定版本的 jar 包。

3.1.3 Sonar GitLab Plugin 配置​

若 sonar-gitlab-plugin 成功安装,则在 SonarQube 的配置页面可以见到如下页面:

具体路径为:登录 admin 账号 -> 点击顶部导航栏【配置】按钮 -> 点击【通用设置】中的【GitLab】选项卡

在该页面中,需要修改以下参数的值:

参数名称参数标识目标值
GitLab urlsonar.gitlab.urlhttp://gitlab.example.com
GitLab User Tokensonar.gitlab.user_tokenGitLab 的用户令牌,获取方式参考 3.2.2
GitLab API versionsonar.gitlab.api_versionv4
info

上述参数中,GitLab User Token 是核心,设置错误的 token,将直接影响到 SonarQube 与 GitLab 的协作。特别要注意的是,生成该 token 的用户 一定要具备管理员权限,否则 SonarQube 无法对 GitLab 上的所有项目进行评论。

3.2 GitLab​

3.2.1 GitLab 安装​

与 SonarQube 相似,我们采用 Docker Compose 的方式安装 GitLab,具体步骤如下:

  • 在任意位置创建安装目录 gitlab,如 /usr/local/gitlab
  • 在安装目录下创建 docker-compose.yml 文件,文件内容如下:
version: '3'
services:
gitlab:
# 使用 gitlab 中文镜像,直接安装 gitlab 中文版
image: 'twang2218/gitlab-ce-zh:11.1.4'
restart: unless-stopped
# 若没有域名,建议直接写ip,否则页面上克隆的复制链接串将显示该值,无法直接使用
hostname: '192.168.117.128'
container_name: gitlab
environment:
# 设置时区
TZ: 'Asia/Shanghai'
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://192.168.117.128'
gitlab_rails['time_zone'] = 'Asia/Shanghai'
ports:
- '80:80'
- '443:443'
- '22:22'
# 将 gitlab 日志文件、数据文件、配置文件存放至宿主机
volumes:
- config:/etc/gitlab
- data:/var/opt/gitlab
- logs:/var/log/gitlab
volumes:
config:
data:
logs:
  • 若宿主机 ssh 端口为默认值 22,则需要将其修改为其他值后,才能继续执行后续步骤,具体修改方式本文略
  • 若宿主机有开启防护墙,需开放上述配置的端口(22 端口默认开启,无需配置):
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --add-port=443/tcp --permanent
firewall-cmd --reload
  • 在安装目录下,使用 docker-compose up -d 命令启动 GitLab,若启动成功,控制台输出如下日志:
Creating network "gitlab_default" with the default driver
Creating gitlab ... done
  • 打开浏览器,输入地址 http://gitlab.example.com 访问 GitLab,若访问成功,则出现如下页面:

info

安装完成后,GitLab会自动生成管理员账号 root,首次登录前需要修改密码。

3.2.2 GitLab 用户令牌生成​

GitLab 安装完成后,我们需要需要根据 3.1.3 中的要求,生成用户令牌。

具体步骤如下:

  • 登录具有管理员权限的账号(一定要是管理员身份)
  • 访问地址 http://gitlab.example.com/profile/personal_access_tokens 进入令牌生成页面
  • 输入令牌名称,勾选 api 、read_user、sudo 权限,点击【创建】按钮,即可生成用户令牌

生成的令牌需要马上保存,后续不再显示,具体令牌信息在如下位置:

3.3 GitLab Runner​

3.3.1 GitLab Runner 安装​

GitLab Runner 是一个处理构建的应用程序,我们需要通过它执行我们在 GitLab CI 中定义的 Job。

在本例中,由于后续编写的 Job 依赖于 Maven 环境,因此选择直接在宿主机上安装 GitLab Runner。

(当然,我们也可以自己构建包含 GitLab Runner 和 Maven 的镜像,然后使用 Docker 安装,具体实现方式本例略。)

在宿主机上安装 GitLab Runner 的步骤如下:

  • 下载 GitLab 官方源:
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash
  • 使用 yum 下载 GitLab Runner:
yum install gitlab-runner

3.3.2 注册与启动 Runner​

注册 Runner 前,我们需要先获取 GitLab 的注册令牌。

登录管理员账号,访问地址 http://gitlab.example.com/admin/runners,即可看到我们想要的注册令牌:

接下来,即可开始注册流程。

首先,执行注册命令:

gitlab-runner register

然后,根据控制台上的提示,我们需要依次输入以下信息:

  • GitLab 地址:http://gitlab.example.com
  • 注册令牌
  • Runner 描述,如 test
  • Runner 标签(与后续编写的 .gitlab-ci.yml 中的 tags 要一致,因此需要慎重填写,当然,写错了也无妨,后续在 UI 界面上可以修改)
  • 选择执行者(ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell)
  • 若执行者选择 shell,则注册流程结束,若执行者选择 docker,则需要选择默认的镜像,如 docker:stable

完成注册后,即可在刚刚的地址中看见该 Runner 的信息:

现在,我们可以使用命令 gitlab-ci-multi-runner run 启动所有 Runner。

3.4 Maven​

Maven 用于执行 SonarQube 的代码检测命令(同样的工具有 Sonar Scanner、Gradle 等)。

由于没有找到已配置好阿里源的 Maven 镜像,所以我们也选择使用本地安装的方式安装 Maven,具体步骤如下:

  • 在任意目录下(如 /usr/local)下载 Maven 二进制包:
wget https://mirror.bit.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
  • 解压压缩包,并将目录重命名为 maven:
tar -xzvf apache-maven-3.6.3-bin.tar.gz
mv apache-maven-3.6.3/ maven
  • 在 /etc/profile 文件追加以下内容:
export M2_HOME=/usr/local//maven
export PATH=$PATH:$M2_HOME/bin
  • 重置环境变量
source /etc/profile

至此,环境要求的所有组件已全部安装完毕。

四、结果验证​

现在,我们通过一次完整的代码提交,来验证自动化代码检测平台是否生效,即:

  • 代码提交时,是否触发 SonarQube 检测作业
  • SonarQube 的检测结果,是否可以反馈至 GitLab

4.1 新建 Maven 工程​

首先,我们创建满足要求的 Maven 工程。该工程的 pom.xml 文件要求具备以下内容:

  • 加入 sonar-maven-plugin 和 jacoco-maven-plugin 插件:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.6.0.1398</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.4</version>
</plugin>
</plugins>
</pluginManagement>
</build>
  • 添加 jacoco-maven-plugin 插件的配置信息:
<profiles>
<profile>
<id>coverage</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

可能有人会有疑问,为什么需要加入 jacoco-maven-plugin 插件呢?这是因为,SonarQube 本身并不支持覆盖率计算,我们需要借助 jacoco 来计算出项目单元测试的覆盖率。

4.2 集成 GitLab-CI​

3.3.2 中,我们演示了如何创建 GitLab Runner。

在这里,我们首先创建执行者为 docker 的 Runner,并将其命名为 docker_runner。

然后,我们编写如下 .gitlab-ci.yml 文件:

image: maven:3.6.3-jdk-8

variables:
SONAR_TOKEN: "${sonar_token}"
SONAR_HOST_URL: "http://sonar.example.com:9000"
GIT_DEPTH: 0

stages:
- build_push
- feedback_to_gitlab

# 执行 SonarQube 分析,并将检测结果推送至 SonarQube
sonarqube_analysis:
stage: build_push
only:
- merge_requests
- master
script:
- mvn --batch-mode verify sonar:sonar -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_TOKEN
tags:
- docker_runner

# 执行 SonarQube 分析,并将检测结果反馈至 GitLab
sonarqube_gitlab_comment:
stage: feedback_to_gitlab
except:
- master
script:
- mvn --batch-mode verify sonar:sonar -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_TOKEN -Dsonar.analysis.mode=preview -Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA -Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME -Dsonar.gitlab.project_id=$CI_PROJECT_ID
tags:
- docker_runner

其中,参数 SONAR_TOKEN 为 SonarQube 的令牌,在 SonarQube 首次创建项目时即可创建。与 GitLab 的令牌一样,此 token 一旦创建,就需要马上保存,否则后续不再显示。

引入该 .gitlab-ci.yml 文件后,当我们提交代码时,上述 Runner 便会根据提交所来源的分支选择相应的执行脚本,具体描述如下:

  • 若提交为主分支提交(或合并至主分支),则执行器 docker_runner 会执行 SonarQube 的分析指令,并将分析结果报送至 SonarQube 平台
  • 若提交为非主分支提交,则执行器 docker_runner 会执行 SonarQube 的分析指令,并将分析结果反馈至 GitLab 中对应的分支下

4.3 提交验证​

现在,我们分别在其他分支和主分支提交代码,查看提交结果。

在提交其他分支代码时,由于我们的代码中有严重 BUG,SonarQube 会在此分支下标记出 BUG 的具体信息,并标记该流水线的状态为失败,如下图所示:

在提交主分支代码时,我们发现执行器自动触发 SonarQube 分析作业,并将检测结果推送至 SonarQube 平台,如下图所示:

综上,我们发现结果符合预期,说明自动化代码检测平台搭建成功,enjoy it!