一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
在安装 Jenkins 之前,我们先装一个 kubernetes 的可视化管理工具,尽管 kubernetes 官方提供了 dashboard UI 界面,但是目前市面上的第三方 UI 库提供的界面更友好,功能更强大,下面我们要介绍的 Kuboard 就是一款比较优秀的工具,这是由 Jumpserver 团队开发的。
安装 Kuboard
在 k8s 上,很多软件都提供了一键式安装方式,前提是有网, Kuboard 也支持一键安装:
kubectl apply -f https://kuboard.cn/install-script/kuboard.yaml
如果没有网的话,可以找地方下载 kuboard.yaml 这个文件,然后再执行,当然里面的镜像也要提前下载好,导入内网。这里有一个不够好的地方就是 kuboard.yaml 默认使用的是 kube-system 命名空间,建议大家创建一个新的命名空间,修改文件内部使用的命名空间。
安装完后,默认使用 Service 对外提供服务,如果我们安装好了 Ingress,也可以使用 Ingress 对外提供服务,默认的服务端口是32567。
执行以下命令获取 Token:
echo $(kubectl -n kube-system get secret $(kubectl -n kube-system get secret | grep kuboard-user | awk '{print $1}') -o go-template='{{.data.token}}' | base64 -d)
注意里面的命名空间,如果我们自己修改了命名空间,这条命令里面也要修改一下
eyJhbGciOiJSUzI1NiIsImtpZCI6ImZVbXM5dkI4a0ZtZEtSeDhtcUlob2Exelh4cjNWVTgyTUpnMVFWSlk4cHMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tbWN4c3MiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhzZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiM2FjZWFjNDYtNTVmOS00OTExLWFkZDYtZDA3NjgyY2UzYWJmIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.ZNTlqYZ2Wp-_ZX8eV7P56tlYOB-viMwZl9g04Hn8PcBPOVVqA5Udsf5xajVjXX-v1x0Gek3hQxZc1ad0MvbFLnQdKeRpbSmbOqg1JPFjB_PybxlaIh15MVrXaEYnociM3YchCE32DpKziHFovJDN2t7mOUlgT5KuJpXydGwuyHrfwbaqRSmOM_spnEonEJrhHh0-1yl48QIARFjHqSOZ868rtm913V9xYPfjJoTZH0yhuSEwwwgsDZABOhw7Lm0lc-Y52I4kWszE1CVkdkTIjAszT_Ir7RCh9WChrz3jsRucJMs9o_RNbZkr3lRQujo4WQpOMNmliL26fSn69qRAqQ
输入 Token 以后登录
k8s 部署 Jenkins
apiVersion: v1
kind: Namespace
metadata:
name: jenkins
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: jenkins-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: jenkins
namespace: jenkins
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: jenkins-master
namespace: jenkins
spec:
replicas: 1
serviceName: jenkins
selector:
matchLabels:
devops: jenkins-master
template:
metadata:
labels:
devops: jenkins-master
spec:
tolerations:
- operator: Exists
serviceAccount: jenkins
initContainers:
- name: fix-permissions
image: busybox
command: ["sh", "-c", "chown -R 1000:1000 /var/jenkins_home"]
securityContext:
privileged: true
volumeMounts:
- name: jenkinshome
mountPath: /var/jenkins_home
containers:
- name: jenkins
image: jenkinsci/blueocean:latest
imagePullPolicy: IfNotPresent
ports:
- name: http #Jenkins Master Web 服务端口
containerPort: 8080
- name: slavelistener #Jenkins Master 供未来 Slave 连接的端口
containerPort: 50000
volumeMounts:
- name: jenkinshome
mountPath: /var/jenkins_home
volumes:
- name: jenkinshome
hostPath:
path: /usr1/jenkins
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: jenkins
spec:
type: NodePort
ports:
- name: http
port: 8080
targetPort: 8080
- name: slavelistener
port: 50000
targetPort: 50000
selector:
devops: jenkins-master
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: jenkins-web
namespace: jenkins
annotations:
Kubernetes.io/ingress.class: nginx
spec:
rules:
- host: www.jenkins.com
http:
paths:
- path: /
backend:
serviceName: jenkins
servicePort: 8080
简单描述一下:
- 创建命名空间,并增加账户管理
- 通过 StatefulSet 创建 Jenkins 服务容器,绑定了持久化存储卷
- 创建 Service 和 Ingress,通过 Ingress 向外提供服务,Service 内的 NodePort 定义可以去掉
安装完成后,如果配置了 Ingress,我们在当前机器上配置好 hosts,就可以通过 www.jenkins.com 去访问了;如果没有配置 Ingress,可以通过节点和端口去访问,执行以下命令查询 NodePort 端口:
kubectl get service -n jenkins
访问登录页面
然后通过以下命令查询管理员密码:
kubectl get pod -n jenkins
kubectl exec jenkins-master-0 -n jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword
登录以后可以按照这篇文章进行配置:Jenkins安装配置
Jenkins 集成 kubernetes (重点)
在使用 Jenkins 的过程中,我们不可能只使用一个 master 节点,必定是要使用多个节点组成集群,传统的 Jenkins 集群需要固定节点,而 kubernetes 的使用将使我们的集群更加灵活,可以即用即走,只有 master 节点需要长期存在,其他节点使用时创建,使用完销毁,合理的利用了资源,又不浪费资源。
安装 kubernetes 插件
在 Jenkins 中安装插件 kubernetes,只安装这一个,其他的就附带安装了。
安装完以后,我们在添加节点的地方使用。
配置地址信息
- kubernetes 地址:这里的地址我们可以通过以下命令去查询
kubectl get nodes -v=7
这里就是我们 kubernetes 的地址,集群内部和外部都可以使用。但是因为我们的 Jenkins 是部署在集群内部的, 所以我们可以使用 kubernetes 的服务发现机制来配置。在 kubernetes 中对外提供 API 服务的是:
kubectl get svc
# kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 40d
在 default 命名空间下,有一个 kubernetes 的 Service,因此在集群内部根据 kubernetes 的路由规则可以采用 kubernetes.default 的方式访问 API,所以这里的配置可以是:
kubernetes.default 和 https://192.168.143.130:6443
- Kubernetes 命名空间:jenkins
- 服务证书:安装 Jenkins 的时候已经指定过 serviceaccount,所以这里不用填
- Jenkins 地址:http://jenkins:8080
- Jenkins 通道:jenkins:5000
配置 Pod Template
- 名称: jnlp-slave
- 命名空间:jenkins
- 标签列表:jnlp-slave,作为 agent 的label 选择使用
- 连接 jenkins 的超时时间(秒):300
- 节点选择器:agent=true,选择指定标签的机器调度
- 工作空间卷:可以使用共享存储,也可以使用临时的
这里我们没有选择镜像,默认会使用 jnlp-slave 的镜像,当我们设置镜像后,默认镜像就不使用了,必须填写
制作工具容器
我们在使用 Pod 作为容器执行机,实际是就是使用 Docker 容器作为 Jenkins 的节点,因为很多时候我们在 Jenkins 的任务中是要制作镜像的,所以需要制作一个工具集合的容器。
FROM alpine
USER root
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && apk update && apk add --no-cache openrc docker git curl tar gcc g++ make bash shadow openjdk8 py-pip python3-dev openssl-dev libffi-dev libstdc++ harfbuzz nss freetype ttf-freefont && mkdir -p /root/.kube && usermod -a -G docker root
COPY requirements.txt /
COPY config /root/.kube/
RUN pip install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r /requirements.txt
RUN rm -rf /var/cache/apk/* && rm -rf ~/.cache/pip
#----安装 kubectl----
COPY kubectl /usr/local/bin/
RUN chmod -x /usr/local/bin/kubectl
创建一个目录,用来存放制作文件
mkdir tools
cd tools
# 拷贝 kubectl 文件和配置文件到当前目录
cp 'which kubectl' .
cp ~/.kube/config .
执行镜像制作命令
docker build -t 192.168.143.130:5000/jnlp-tools:latest .
docker push 192.168.143.130:5000/jnlp-tools:latest
然后我们在节点配置里,把镜像配置上
在 tools 容器中我们可能要执行 docker 命令,所以要挂载本机的 /var/run/docker.sock 文件
kubernetes 搭建 sonarqube 扫描环境
apiVersion: v1
kind: Service
metadata:
name: sonarqube
namespace: jenkins
labels:
app: sonarqube
spec:
ports:
- name: sonarqube
port: 9000
targetPort: 9000
protocol: TCP
selector:
app: sonarqube
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: jenkins
name: sonarqube
labels:
app: sonarqube
spce:
replicas: 1
selector:
matchLabels:
app: sonarqube
template:
metadata:
labels:
app: sonarqube
spec:
nodeSelector:
sonar: true
initContainers:
- name: elasticsearch-logging-init
image: alpine: 3.6
command:
- /sbin/sysctl
- -w
- vm.max_map_count=262144
resources: {}
securityContext:
privileged: true
containers:
- name: sonarqube
image: sonarqube: 7.9.5-community
ports:
- containerPort: 9000
env:
- name: SONARQUBE_JDBC_USERNAME
value: root
- name: SONARQUBE_JDBC_PASSWORD
value: 123456
- name: SONARQUBE_JDBC_URL
value: "jdbc: mysql://ip:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false"
livenessProbe:
httpGet:
path: /sessions/new
port: 9000
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /sessions/new
port: 9000
initialDelaySeconds: 60
periodSeconds: 30
failureThreshold: 6
resources:
limits:
cpu: 2000m
memory: 4096Mi
requests:
cpu: 300m
memory: 512Mi
volumes:
- name: sonarqube-data
hostPath:
path: /opt/sonarqube/data
- name: sonarqube-logs
hostPath:
path: /opt/sonarqube/logs
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: sonarqube
namespace: jenkins
spec:
rules:
- host: www.sonar.com
http:
paths:
- path: /
backend:
serviceName: sonarqube
servicePort: 9000
小技巧:
- 导出 Jenkins 已安装插件列表
# 账号:admin,密码:123456,Jenkins-master地址:xx.xx.xx.xx
curl -sSL "http://admin:123456@xx.xx.xx.xx:8080/pluginManager/api/xml?depth=1&xpath=/*/*/shortName|/*/*/version&wrapper=plugins" | perl -pe 's/.*?<shortName>([\w-]+).*?<version>([^<]+)()(</\w+>)+/\1:\2\n/g'|sed 's/ /:/' > plugins.txt
然后在其他安装了 Jenkins 的机器上执行以下命令,就可以安装好指定插件了
/usr/local/bin/install-plugins.sh < plugins.txt