在Kubernetes中,利用helm部署应用非常的方便,它就类似于Debian/Ubuntu中的apt,在Helm Hub中找到你需要的程序,然后快速部署。我使用它安装了Jenkins,用了一段时间之后,发现以下两个问题实在是让人无法接受,我决定放弃使用Helm部署,改用Deployment的方式。
重启时间特别长
初次安装的时间稍长,我觉得可以忍受,但重启的时候基本要花10分钟才能到Jenkins主服务启动,因为在主服务启动之前initContainer有一些工作要做,等到最后主服务启动之后我看了以下Age字段,基本接近十分钟。
这个重启的时间让我非常难以接受,因为这个时间远比非容器化部署方案要高很多。
我清楚这其中的原因是因为它要干很多事,初始化很多步骤才能让我们轻松一条命令就能启动一个Jenkins服务,但重启的事件其实是经常发生的,比如节点故障造成Pod迁移,或者其它未知异常造成的Pod重启是在日常运行中经常遇见的情况,显然省了初始化安装工作而带来的每次重启的长时间等待显然不划算
配置还原
具体情况是这样的,每次无论因任何情况下的重启,我都发现有两个问题
- 配置 -> Jenkins Location -> Jenkins URL 这个值会被改写成默认的Service Name
- 云配置全部被还原
这个问题让我彻底放弃helm的Hub的东西,这简直是底线了。
第一个问题,发现的影响是页面会提示
It appears that your reverse proxy set up is broken
这个很容易理解,因为我们访问Jenkins是通过暴露的Ingress访问,URL上的host与填写在配置里的Jenkins URL不一致
第二个问题,云的所有配置被还原
因为我使用自定义的Image,并且各项参数也不一样,每次被还原,我就得重新配置云端的配置将近需要二十多分钟。要说前面的Jenkins URL配置还原还好,这不会导致Jenkins不能工作,但云端的配置被还原就彻底不能工作了。
分析
这其实跟Helm没关系,是跟我用的stable/Jenkins有关系,Jenkins这个Chart为了确保在安装Jenkins之后完成很多初始化工作,比如密码重置,比如默认安装上Kubernetes插件等等。
但工作的越多,可能越容易出现问题,每一次启动花费的时间也漫长,所以我只能说目前的stable/Jenkins还不是那么友好,我的解决方法是改用Deployment方式部署
Deployment部署Jenkins
Jenkins有提供官方的镜像在Docker Hub上,我们直接用就好,采用这种方式安装需要在第一次部署成功之后要登录网页初始化一些配置,以及要手动安装Kubernetes插件并且到云端配置相关信息。
一个非常诱人的好处是这种方式非常稳定,并且重启仅需十多秒,大大的相比之前十分钟,简直爽翻了。下面是YAML例子
deployment.yaml
apiVersion: v1
kind: Namespace
metadata:
name: jenkins
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: jenkins
name: jenkins
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jenkins
namespace: jenkins
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list","watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
- apiGroups: [""]
resources: ["configmap"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins
namespace: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins
subjects:
- kind: ServiceAccount
name: default
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-home
namespace: jenkins
spec:
accessModes:
- ReadWriteOnce
storageClassName: jenkins
resources:
requests:
storage: 100Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: master-deployment
namespace: jenkins
labels:
app: master
spec:
replicas: 1
selector:
matchLabels:
app: master
template:
metadata:
labels:
app: master
spec:
containers:
- name: jenkins
image: jenkins/jenkins:lts
env:
- name: TZ
value: Asia/Shanghai
ports:
- containerPort: 8080
- containerPort: 50000
volumeMounts:
- name: data
mountPath: /var/jenkins_home
volumes:
- name: data
persistentVolumeClaim:
claimName: "jenkins-home"
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: jenkins
spec:
selector:
app: master
ports:
- name: web
port: 8080
targetPort: 8080
- name: ci
port: 50000
targetPort: 50000
前面的ServiceAccount、Role和RoleBinding是为了给Kubernetes插件使用的,因为在有新的Build工作时,Kubernetes插件会利用这些信息动态创建一个Pod去Running我们的工作,结束后会自动释放掉。这个就跟我们使用Helm安装stable/Jenkins效果一样。