本文搭建的 SonarQube 版本是 7.4.9-community,因为在官方文档中声明 7.9 版本以后就再也不支持使用 MySQL 数据库。因此这次搭建使用的数据库是 PostgreSQL 11.4 版本。html
将 PostgreSQL 和 SonarQube 放在同一个命名空间 ns-sonar 中,建立命名空间的 yaml 文件以下:node
--- apiVersion: v1 kind: Namespace metadata: name: ns-sonar labels: name: ns-sonar
为了实现 PostgreSQL 数据的持久化存储,须要将数据存放在本地存储中。首先在宿主机的 /opt/ops_ceph_data 目录下建立以下目录:web
mkdir -p /opt/ops_ceph_data/sonarqube/{PostgreSQL_data,sonar}
在个人机器环境中,/opt/ops_ceph_data 是挂载的 cephfs 文件系统,因此在任意节点上建立目录后,其余节点上都会存在。这也保证了 PostgreSQL 容器能够在任意节点上进行漂移。sql
同时因为我是将 cephfs 直接挂载到物理机上,因此在下面建立 pv 的时候,指定的存储类型是 local。数据库
若是但愿学习如何搭建 Ceph 集群,能够参考个人另外一篇博文:CentOS 7 搭建 Ceph 集群(nautilus 版本)api
建立 PV 和 PVC 的 yaml 文件内容以下:bash
--- 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
因为上面配置的 PV 存储类型是 local,因此须要在容许运行 PostgreSQL 容器的 Node 上设置 labels,labels 为 sonar-node=true
,这里我是将全部的 Node 节点上都添加了这个 label,命令以下:session
for i in 1 2 3 4 5 do kubectl label nodes k8s-node${i} sonar-node=true done
注意,PV 中配置的 matchExpressions 必定要与 labels 一致,否则会没法匹配。app
接下来须要配置用于映射 PostgreSQL 容器端口的 Service 文件,这里我使用 NodePort 类型,yaml 文件内容以下:ide
--- 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
由于我搭建的环境中,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 没有生效如今还不清楚,后续查出缘由后再补充。
使用容器搭建 PostgreSQL 服务,默认会在容器内监听 0.0.0.0 地址,因此像传统方式部署那样去手动修改监听地址。
在其余机器中验证链接 PostgreSQL,IP 地址为任意 Node 节点 IP。用户名密码和数据库名称参考上面的 yaml 文件。测试是否能够正常链接便可。
用于 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
使用 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
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 文件有些配置须要进行以下说明。
initContainers 就是初始化容器,也就是在主容器启动以前,首先启动初始化容器。若是有多个初始化容器,会按照定义的顺序依次启动。只有在初始化容器启动完成后,主容器才会启动。
使用初始化容器有以下几个做用:
须要注意的是,initContainers 是以 sideCar 模式运行在 Pod 中的。
关于健康检查策略,上面的 yaml 文件中已经给出了一些注释。其余的配置项能够参考官网文档:配置存活探针和就绪探针
上面的 yaml 文件中在存储挂载的部分使用了 subPath 配置,这是由于 SonarQube 中一共有三个须要挂载的目录:
而宿主机上的存储目录只提供了一个 /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
SonarQube 部署完成后,能够经过任意 Node 节点的 IP 地址加上映射的端口访问。
默认的登陆用户名和密码均为 admin。登陆完成后,首先点击 Administration --> Marketplace ,在 Plugin 部分查找 chinese 插件和 Codehawk Java 进行安装。chinese 插件用于汉化界面,安装完成后须要重启服务(在页面上方会有提示)。