在 k8S 中搭建 SonarQube 7.4.9 版本(使用 PostgreSQL 数据库)
搭建 SonarQube 和 PostgreSQL 服务
本文搭建的 SonarQube 版本是 7.4.9-community,由于在官方文档中声明 7.9 版本之后就不再支持使用 MySQL 数据库。所以此次搭建使用的数据库是 PostgreSQL 11.4 版本。
一、部署 PostgreSQL 服务
1. 创建命名空间
将 PostgreSQL 和 SonarQube 放在同一个命名空间 ns-sonar 中,创建命名空间的 yaml 文件如下:
---
apiVersion: v1
kind: Namespace
metadata:
name: ns-sonar
labels:
name: ns-sonar
2. 创建 PostgreSQL 使用的 PV 和 PVC
为了实现 PostgreSQL 数据的持久化存储,需要将数据存放在本地存储中。首先在宿主机的 /opt/ops_ceph_data 目录下创建如下目录:
mkdir -p /opt/ops_ceph_data/sonarqube/{PostgreSQL_data,sonar}
在我的机器环境中,/opt/ops_ceph_data 是挂载的 cephfs 文件系统,所以在任意节点上创建目录后,其他节点上都会存在。这也保证了 PostgreSQL 容器可以在任意节点上进行漂移。
同时由于我是将 cephfs 直接挂载到物理机上,所以在下面创建 pv 的时候,指定的存储类型是 local。
创建 PV 和 PVC 的 yaml 文件内容如下:
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgresql-pv
namespace: ns-sonar
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 5Gi
local:
path: /opt/ops_ceph_data/sonarqube/PostgreSQL_data
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: sonar-node
operator: In
values:
- "true"
persistentVolumeReclaimPolicy: Retain
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgresql-pvc
namespace: ns-sonar
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
3. 配置 labels
由于上面配置的 PV 存储类型是 local,所以需要在允许运行 PostgreSQL 容器的 Node 上设置 labels,labels 为 sonar-node=true
,这里我是将所有的 Node 节点上都添加了这个 label,命令如下:
for i in 1 2 3 4 5
do
kubectl label nodes k8s-node${i} sonar-node=true
done
注意,PV 中配置的 matchExpressions 一定要与 labels 一致,不然会无法匹配。
4. 创建 Service
接下来需要配置用于映射 PostgreSQL 容器端口的 Service 文件,这里我使用 NodePort 类型,yaml 文件内容如下:
---
apiVersion: v1
kind: Service
metadata:
name: postgresql-service
namespace: ns-sonar
labels:
app: postgresql
spec:
type: NodePort
ports:
- port: 5432
targetPort: 5432
nodePort: 30543
protocol: TCP
selector:
app: postgresql
5. 创建 PostgreSQL 的 Pod
因为我搭建的环境中,PostgreSQL 使用的单点模式,所以直接使用 Deployment 类型来创建 Pod,yaml 文件内容如下:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgresql
namespace: ns-sonar
labels:
app: postgresql
spec:
replicas: 1
selector:
matchLabels:
app: postgresql
template:
metadata:
labels:
app: postgresql
spec:
containers:
- name: postgresql-for-sonar
image: postgres:11.4
imagePullPolicy: "IfNotPresent"
ports:
- containerPort: 5432
env: # 这里设置 PostgreSQL 启动时候所需要的环境变量
- name: POSTGRES_DB # 定义要创建的数据库名称
value: sonarDB
- name: POSTGRES_USER # 定义要创建访问数据库的用户
value: sonarUser
- name: POSTGRES_PASSWORD # 定义数据库的密码
value: sonar_admin
resources:
limits:
cpu: 1000m
memory: 2048Mi
requests:
cpu: 500m
memory: 1024Mi
volumeMounts:
- mountPath: /var/lib/postgresql/data # 这个目录是 PostgreSQL 容器内默认的数据存储路径
name: postgredb
volumes:
- name: postgredb
persistentVolumeClaim:
claimName: postgresql-pvc # 将上面创建的 PVC 挂载到 PostgreSQL 的数据目录下
在环境变量设置的部分,我一开始使用的是引用 Secret 的方式,但是在容器启动后没有正确创建用户和密码。所以还是使用了直接指定 value 的方式。具体为什么 Secret 没有生效现在还不清楚,后续查出原因后再补充。
6. 验证数据库连接
使用容器搭建 PostgreSQL 服务,默认会在容器内监听 0.0.0.0 地址,所以像传统方式部署那样去手动修改监听地址。
在其他机器中验证连接 PostgreSQL,IP 地址为任意 Node 节点 IP。用户名密码和数据库名称参考上面的 yaml 文件。测试是否可以正常连接即可。
二、部署 SonarQube 服务
1. 创建 SonarQube 使用的 PV 和 PVC
用于 SonarQube 的持久化存储目录已经在前面创建好了,下面直接编写 yaml 文件,内容如下:
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: sonar-pv
namespace: ns-sonar
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 20Gi
local:
path: /opt/ops_ceph_data/sonarqube/sonar_data
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: sonar-node
operator: In
values:
- "true"
persistentVolumeReclaimPolicy: Retain
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: sonar-pvc
namespace: ns-sonar
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
需要注意的是,PV 中匹配的 labels 已经在前面创建好了,所以此处不需要重复设置 labels。
另外 SonarQube 容器运行的时候,不是以 root 用户运行的,所以需要确保挂载的目录要允许其他用户读写,否则容器启动会失败。
chmod -R 777 /opt/ops_ceph_data/sonarqube/sonar_data
2. 创建 Service
使用 NodePort 类型将 SonarQube 端口映射出来,yaml 文件内容如下:
---
apiVersion: v1
kind: Service
metadata:
name: sonarqube-service
labels:
app: sonarqube-service
spec:
type: NodePort
ports:
- port: 9000
targetPort: 9000
nodePort: 30900
protocol: TCP
selector:
app: sonarqube
3. 创建 SonarQube 的 Pod
SonarQube 的 Pod 使用 Deployment 来创建,yaml 文件内容如下:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sonarqube
namespace: ns-sonar
labels:
app: sonarqube
spec:
replicas: 1
selector:
matchLabels:
app: sonarqube
template:
metadata:
labels:
app: sonarqube
spec:
initContainers: # 设置初始化镜像,用于执行 system 命令,此处的配置在下文会有说明
- name: init-sysctl
image: busybox
imagePullPolicy: IfNotPresent
command: ["sysctl", "-w", "vm.max_map_count=262144"] # 设置vm.max_map_count这个值调整内存权限,否则启动可能报错
securityContext:
privileged: true # 设置可以以 root 权限执行命令
containers:
- name: sonarqube
image: sonarqube:7.9.4-community
ports:
- containerPort: 9000
env:
- name: SONARQUBE_JDBC_USERNAME # 设置 SonarQube 连接数据库使用的用户名
value: sonarUser
- name: SONARQUBE_JDBC_PASSWORD # 设置 SonarQube 连接数据库使用的密码
value: sonar_admin
- name: SONARQUBE_JDBC_URL # 设置 SonarQube 连接数据库使用的地址
value: "jdbc:postgresql://10.16.12.206:30543/sonarDB" # 这里可以指定 Node 节点的 IP 地址和 PostgreSQL 映射出来的端口
livenessProbe: # 设置容器存活检查策略,如果失败将杀死容器,然后根据 Pod 的 restartPolicy 来决定是否进行重启操作
httpGet:
path: /sessions/new
port: 9000
initialDelaySeconds: 60 # 设置在容器启动多长时间后开始探针检测,此处设置为 60s
periodSeconds: 30 # 设置探针检查的频率,此处设置为每 30s 检查一次
readinessProbe: # 设置容器的就绪检查策略,查看容器是否准备好接受 HTTP 请求
httpGet:
path: /sessions/new
port: 9000
initialDelaySeconds: 60 # 设置在容器启动多长时间后开始探针检测,此处设置为 60s
periodSeconds: 30 # 设置探针检查的频率,此处设置为每 30s 检查一次
failureThreshold: 6 # 在检查失败的情况下,重复检查的次数,此处设置为 6
resources:
limits:
cpu: 2000m
memory: 2048Mi
requests:
cpu: 1000m
memory: 1024Mi
volumeMounts:
- mountPath: /opt/sonarqube/conf
name: sonarqube
subPath: conf # 使用 subPath 在宿主机的挂载目录上设置一个子目录,用于存放上面指定目录的数据
- mountPath: /opt/sonarqube/data
name: sonarqube
subPath: data
- mountPath: /opt/sonarqube/extensions
name: sonarqube
subPath: extensions
volumes:
- name: sonarqube
persistentVolumeClaim:
claimName: sonar-pvc #绑定上面创建的 PVC
对于上面的 yaml 文件有些配置需要进行说明。
3.1 initContainers
initContainers 就是初始化容器,也就是在主容器启动之前,首先启动初始化容器。如果有多个初始化容器,会按照定义的顺序依次启动。只有在初始化容器启动完成后,主容器才会启动。
使用初始化容器有如下几个作用:
- 为主容器初始化环境:例如本文中的例子,由于 SonarQube 在启动服务的时候,要确保已经设置了 vm.max_map_count 这个值,但是由于 SonarQube 镜像本身不能执行这个命令,所以可以使用一个初始化容器来执行该命令(同一个Pod下的容器是共享文件系统的),并且保证该命令已经执行完成的情况下,主容器才会启动。或者另一种情况是主容器启动的时候需要安装一些依赖包,为了避免安装依赖包时间过长,影响健康检查策略,可以选择将这个安装的任务交给初始化容器去执行。
- 等待其他服务 Ready:例如一个 web 服务的 Pod 启动时,需要确保另一个数据库服务的 Pod 已经启动了并且可以接受连接(不然 web 服务可能会报错或者启动失败),所以可以在 web 服务的 Pod 中部署一个初始化容器,去检查数据库服务是否已经准备好,直到数据库可以开始连接,初始化容器才会推出。
- 初始化集群配置:例如可以使用初始化容器检测当前业务集群中已经存在的节点信息,并为主容器准备好集群的配置信息,这样集群启动时就可以根据这个配置信息加入到集群中。
需要注意的是,initContainers 是以 sideCar 模式运行在 Pod 中的。
3.2 健康检查策略
关于健康检查策略,上面的 yaml 文件中已经给出了一些注释。其他的配置项可以参考官网文档:配置存活探针和就绪探针
3.3 subPath 配置
上面的 yaml 文件中在存储挂载的部分使用了 subPath 配置,这是因为 SonarQube 中一共有三个需要挂载的目录:
- /opt/sonarqube/conf
- /opt/sonarqube/data
- /opt/sonarqube/extensions
而宿主机上的存储目录只提供了一个 /opt/ops_ceph_data/sonarqube/sonar_data,默认情况下,以上三个目录的数据都会存储在宿主机这一个目录下,这样就会造成数据混乱,没有办法区分某个数据文件或目录具体是哪个父目录下的。可以使用 subPath 配置解决这个问题,这个配置的功能就是在宿主机的挂载目录下创建一个子目录来存放对应目录的数据。
例如上面的 subPath 配置项分别创建了三个子目录:conf、data、extensions,那么在宿主机的挂载目录下显示的就是如下形式:
[@k8s-master1 ~]# ll /opt/ops_ceph_data/sonarqube/sonar_data/
总用量 0
drwxrwxrwx 1 root root 0 10月 29 11:41 conf
drwxrwxrwx 1 root root 2 10月 29 15:57 data
drwxrwxrwx 1 root root 2 10月 29 16:01 extensions
这三个子目录的名称可以随意指定,上面的 yaml 文件中 subPath 指定的子目录名称与容器中的目录名称一致是为了更方便的区分。如果将 subPath 的配置分别改为:sonar_conf、sonar_data、sonar_extensions,那么在宿主机挂载目录下显示的就会是如下形式:
[@k8s-master1 ~]# ll /opt/ops_ceph_data/sonarqube/sonar_data/
总用量 0
drwxrwxrwx 1 root root 0 10月 29 11:41 sonar_conf
drwxrwxrwx 1 root root 2 10月 29 15:57 sonar_data
drwxrwxrwx 1 root root 2 10月 29 16:01 sonar_extensions
4. 访问 SonarQube 并安装插件
SonarQube 部署完成后,可以通过任意 Node 节点的 IP 地址加上映射的端口访问。
默认的登录用户名和密码均为 admin。登录完成后,首先点击 Administration --> Marketplace ,在 Plugin 部分查找 chinese 插件和 Codehawk Java 进行安装。chinese 插件用于汉化界面,安装完成后需要重启服务(在页面上方会有提示)。
在 k8S 中搭建 SonarQube 7.4.9 版本(使用 PostgreSQL 数据库)的更多相关文章
- 在k8s中搭建可解析hostname的DNS服务
2016-01-25更新 上篇文章总结k8s中搭建hbase时,遇到Pod中hostname的DNS解析问题,本篇将通过修改kube2sky源码来解决这个问题. 1 前言 kube2sky在Githu ...
- 在 k8s 中的 jenkins 集成 sonarqube 实现代码质量检查
不乱于心,不困于情,不畏将来,不念过往,如此安好 --<不宠无惊过一生>丰子恺 概述 关于在 k8s 中安装 jenkins 和 sornarqube 可以查看下面的文章: 在 k8s 中 ...
- 轻松搭建自己的Linux发行版本
许多人想要搭建自己的Linux发行版本,可能是觉得有趣,也可能是为了学习更多的Linux知识,或者因为他们有很正式的问题要解决.但是秘密是:自己搭建完美的发行版本不是很困难的一件事.事实上,我们收集了 ...
- k8s中的dns服务发现
一.dns服务 1.解决的问题 为了通过服务的名字在集群内进行服务相互访问,需要创建一个dns服务 2.k8s中使用的虚拟dns服务是skydns 二.搭建 1.创建并应用skydns-rc.yaml ...
- Alibaba Nacos 学习(五):K8S Nacos搭建,使用nfs
Alibaba Nacos 学习(一):Nacos介绍与安装 Alibaba Nacos 学习(二):Spring Cloud Nacos Config Alibaba Nacos 学习(三):Spr ...
- Kubernetes之在k8s中部署Java应用
部署好了k8s以后 部署参考https://www.cnblogs.com/minseo/p/12055731.html 怎么在k8s部署应用 项目迁移到k8s平台是怎样的流程 1,制作镜像 2,控制 ...
- Docker & k8s 系列二:本机k8s环境搭建
本篇将会讲解k8s是什么?本机k8s环境搭建,部署一个pod并演示几个kubectl命令,k8s dashboard安装. k8s是什么 k8s是kubernetes的简写,它是一个全新的基于容器技术 ...
- Docker & k8s 系列三:在k8s中部署单个服务实例
本章将会讲解: pod的概念,以及如何向k8s中部署一个单体应用实例. 在上面的篇幅中,我们了解了docker,并制作.运行了docker镜像,然后将镜像发布至中央仓库了.然后又搭建了本机的k8s环境 ...
- 在kubernetes中搭建harbor,并利用MinIO对象存储保存镜像文件
前言:此文档是用来在线下环境harbor利用MinIO做镜像存储的,至于那些说OSS不香吗?或者单机harbor的,不用看了.此文档对你没啥用,如果是采用单机的harbor连接集群MinIO,请看我的 ...
随机推荐
- 【Flutter 实战】大量复杂数据持久化
老孟导读:上一篇文章讲解了 Android 和 iOS 的文件目录系统,此篇文章讲解如何使用 SQLite 保存数据. 欢迎大家投稿:http://laomengit.com/plan/Contrib ...
- 如何下载jmeter旧版本
推荐先用旧版本做好测试基本操作,因为高版本不适合做压力测试,需要证书,有点麻烦. 1.百度或直接打开jmeter官网:https://jmeter.apache.org/ 2.向下拖到Archives ...
- 普转提Day2
T1 给定一个区间,求这个区间中只有一个数字与其他数组不相同的数的个数. 给出的区间范围较大,但是要求的数比较少.所以我的想法是这样的:因为这些数只有一个数字和每个数字都相同的数不同,所以考虑将所有数 ...
- 用JTable 实现日历
效果图: 主要思想:日历最核心的功能就是能显示某年某月对应的日期和星期几.因此只要实现传入具体的年份和月份,得到一组存放了日期的数组a[ ]即可.其中数组的大小设置成42,要考虑的问题是当月的第一天对 ...
- 05 sublime环境配置及编译运行后输出中文乱码的解决
编译后的乱码问题 编译后的输出:中文显示异常: 编译C出现乱码问题解决 解决思路:解决办法很简单,就是先设置文件编码为GBK格式,之后再输入中文文字,运行时的中文就不是乱码了. 首先,sublime中 ...
- matlab中upper 将字符串转换为大写
参考:https://ww2.mathworks.cn/help/matlab/ref/fprintf.html?searchHighlight=fprintf&s_tid=doc_srcht ...
- 带有Firebase的离子2:在OAuth 2中签名
介绍 这是一个指南,展示如何在Android上使用Firebase认证谷歌用户. 背景 虽然很多人都写过这个指南,但是他们没有解释一个关键的部分--为什么在执行了每一步之后仍然会看到认证错误12501 ...
- GDB 调试 .NET 程序实录 - .NET 调用 .so 出现问题怎么解决
注:本文重要信息使用 *** 屏蔽关键字. 最近国庆前,项目碰到一个很麻烦的问题,这个问题让我们加班到凌晨三点. 大概背景: 客户给了一些 C语言 写的 SDK 库,这些库打包成 .so 文件,然后我 ...
- ASP.Net Core3.1 生成二维码填坑
ASP.Net Core3.1 使用QrCode生成二维码 部署到Linux报错 The type initializer for 'System.DrawingCore.GDIPlus' threw ...
- php超全局数组 为什么swoole的http服务不能用
php的超全局数组$_GET等九个 可以直接使用 无需定义 实际上是浏览器请求到Apache或者nginx的时候 转发到PHP处理模块 fpm转发给php解释器处理 php封装好后丢给php的 sw ...