K8S + GitLab + Jenkins自动化发布项目实践(二)
前置工作:已部署5节点k8s集群,并搭建了代码仓库和镜像仓库(GitLab + Harbor)。
| 主机名 | IP | 角色 |
|---|---|---|
| k8s-master1 | 192.168.124.a | k8s控制平面 |
| k8s-master2 | 192.168.124.b | k8s控制平面 |
| k8s-master3 | 192.168.124.c | k8s控制平面 |
| k8s-worker1 | 192.168.124.d | k8s工作节点 |
| k8s-worker2 | 192.168.124.e | k8s工作节点 |
| harborgit | 192.168.124.f | 代码仓库 & 镜像仓库 |
Jenkins是一款开源的、用于自动化构建、测试和部署的CI-CD工具。
🔥配置参考:https://blog.csdn.net/Sebastien23/article/details/126276294
在工作节点k8s-worker1上部署NFS服务器:
[root@k8s-worker1 ~]# mkdir -p /ifs/kubernetes
[root@k8s-worker1 ~]# yum install nfs-utils -y
[root@k8s-worker1 ~]# vi /etc/exports
/ifs/kubernetes *(rw,sync,no_root_squash)
[root@k8s-worker1 ~]# systemctl start nfs
[root@k8s-worker1 ~]# systemctl enable nfs
在其他工作节点挂载NFS共享目录:
[root@k8s-worker2 ~]# mkdir -p /ifs/kubernetes
[root@k8s-worker2 ~]# yum install nfs-utils -y
[root@k8s-worker2 ~]# echo '192.168.124.d:/ifs/kubernetes /ifs/kubernetes nfs4 defaults 0 0' >> /etc/fstab
[root@k8s-worker2 ~]# mount -a
修改目录权限:
[root@k8s-worker1 ~]# mkdir /ifs/kubernetes/jenkins
[root@k8s-worker1 ~]# chmod -R 777 /ifs/kubernetes
定义一个nfs类型的PV资源:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-jenkins
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
nfs:
path: /ifs/kubernetes/jenkins
server: 192.168.124.d
创建PV资源:
[root@k8s-master1 jenkins]# kubectl apply -f pv-nfs-jenkins.yml
persistentvolume/pv-nfs-jenkins created
[root@k8s-master1 jenkins]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-jenkins 5Gi RWX Retain Available 6s
通过Deployment控制器来部署Jenkins官方镜像,会对外暴露8080(Web访问端口)和50000(Slave通信端口)两个端口。Jenkins容器的数据存储默认在/var/jenkins_home目录下,需要对该目录进行PV持久化。
🚋官方镜像地址:https://hub.docker.com/r/jenkins/jenkins
🚋部署配置:https://www.jenkins.io/doc/book/installing/kubernetes/
我们使用jenkins.yml来部署Jenkins容器,通过PVC来请求PV资源,同时定义好Service访问和RBAC服务账号权限。
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
spec:
replicas: 1
selector:
matchLabels:
name: jenkins
template:
metadata:
name: jenkins
labels:
name: jenkins
spec:
serviceAccountName: jenkins
containers:
- name: jenkins
image: jenkins/jenkins:lts
ports:
- containerPort: 8080
- containerPort: 50000
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
securityContext:
fsGroup: 1000
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
spec:
selector:
name: jenkins
type: NodePort
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
nodePort: 30008
- name: agent
port: 50000
protocol: TCP
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: default
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jenkins
namespace: default
rules:
- apiGroups: [""]
resources: ["pods","events"]
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","events"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
namespace: default
部署Jenkins容器:
[root@k8s-master1 jenkins]# kubectl apply -f jenkins.yml
deployment.apps/jenkins created
persistentvolumeclaim/jenkins created
service/jenkins created
serviceaccount/jenkins created
role.rbac.authorization.k8s.io/jenkins created
rolebinding.rbac.authorization.k8s.io/jenkins created
部署完成后,通过查看Pod日志来获取Jenkins初始化的管理员口令:
kubectl get pods
kubectl logs <jenkins-pod-name>
# 也可以在宿主机的以下路径找到
cat /ifs/kubernetes/jenkins/secrets/initialAdminPassword
通过暴露的NodePort访问Jenkins首页,我这里是http://192.168.124.a:30008。
[root@k8s-master1 jenkins]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins NodePort 10.106.152.176 <none> 80:30008/TCP,50000:30282/TCP 22m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
在自定义Jenkins界面,选择插件来安装(不要安装推荐的插件),选择“无”来取消自动勾选的所有插件。

定义好管理员用户和实例信息后,来到Jenkins首页。

在Manage Jenkins → \rightarrow →System Configuration → \rightarrow →Manage Plugins → \rightarrow →Available plugins中分别搜索安装以下插件(install without restart):

Jenkins下载插件默认服务器在国外,如果下载速度很慢,可以修改为国内源:
cd /ifs/kubernetes/jenkins/updates
sed -i 's/https:\/\/updates.jenkins.io\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json
然后通过浏览器重启Jenkins:
http://NodeIP:30008/restart
如果重启Jenkins Pod所在服务器后,Jenkins容器状态一直为Unknown,可以直接删除Pod,Deployment控制器会重新再创建一个新的Pod。而且由于/var/jenkins_home被挂载在NFS存储中,也不用担心丢失Jenkins数据。
[root@k8s-master1 jenkins]# kubectl get pods,deploy
NAME READY STATUS RESTARTS AGE
pod/jenkins-5bddd99684-w9glp 0/1 Unknown 5 11h
pod/jenkins-slave-nhfbm-0xd6f 0/1 ContainerCreating 0 58m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/jenkins 0/1 1 0 11h
[root@k8s-master1 jenkins]# kubectl delete pod/jenkins-5bddd99684-w9glp
pod "jenkins-5bddd99684-w9glp" deleted
Master(Jenkins本身)提供Web页面来让用户管理项目和Slave(从节点)。项目任务可以运行在Master本机,也可以分配到从节点运行。一个Master可以关联多个Slave。Slave节点起到了分担工作任务和隔离构建环境的作用。
当触发Jenkins任务时,Jenkins会调用Kubernetes API创建Slave Pod。Slave Pod启动后会连接Jenkins,接受任务处理。
Kubernetes插件用于Jenkins在k8s集群中运行动态代理。
🌻插件介绍:https://github.com/jenkinsci/kubernetes-plugin
配置插件:Manage Jenkins → \rightarrow →Manage Nodes and Clouds → \rightarrow →Configure Clouds中添加Kubernetes。
点击打开Kubernetes Cloud Details,输入Kubernetes地址:
https://kubernetes.default
表示default命名空间中的kubernetes服务,并点击“连接测试”,出现Connected to Kubernetes v1.x.x即表示连接成功。
最后输入Jenkins地址并保存。
http://jenkins.default
Jenkins Slave工作需要用到OpenJDK、Maven、git命令、kubectl命令、以及docker build和docker push命令。由于我们的k8s集群使用的容器运行时为containerd,自带的crictl工具不支持build和push操作,因此需要安装nerdctl工具。
🐻Nerdctl官方下载地址:https://github.com/containerd/nerdctl/releases
查看containerd版本:
kubectl get nodes -o wide
#CONTAINER-RUNTIME中的版本信息为containerd://1.6.18
下载兼容的nerdctl版本,并解压到/usr/local目录下:
tar Cxzvvf /usr/local nerdctl-full-1.2.1-linux-amd64.tar.gz
启动nerdctl和buildkit服务:
nerdctl run -d --name nginx -p 80:80 nginx:alpine
# nerdctl使用buildkit服务来build镜像
systemctl enable buildkit.service --now
用于构建Jenkins Slave镜像的Dockerfile如下:
FROM centos:7
LABEL maintainer kratos
RUN yum install -y java-1.8.0-openjdk maven git libtool-ltdl-devel && \
yum clean all && \
rm -rf /var/cache/yum/* && \
mkdir -p /usr/share/jenkins
COPY slave.jar /usr/share/jenkins/slave.jar
COPY jenkins-slave /usr/bin/jenkins-slave
COPY settings.xml /etc/maven/settings.xml
RUN chmod +x /usr/bin/jenkins-slave
COPY kubectl /usr/bin/
ENTRYPOINT ["jenkins-slave"]
其中:
slave.jar为agent程序,用于接收master下发的任务。jenkins-slave是用于启动slave.jar的Shell脚本。settings.xml配置中需要将Maven官方源修改为阿里云源。kubectl客户端工具。在Dockerfile同级目录下准备好要打包进镜像的文件。
[root@k8s-master1 jenkins]# ls
Dockerfile jenkins-slave kubectl settings.xml slave.jar
构建镜像并推送到Harbor镜像仓库:
# 注意命令最后面的'.'
nerdctl build -t 192.168.124.f/library/jenkins-slave-jdk:1.8 .
nerdctl push 192.168.124.f/library/jenkins-slave-jdk:1.8
推送成功后在Harbor仓库中可以看到上传的镜像。
如果推送失败,报错类似如下:
ERRO[0000] server "192.168.124.f" does not seem to support HTTPS error="failed to do request: ...
... dial tcp 192.168.124.f:443: connect: connection refused
... unexpected status from GET request to https://auth.docker.io/token?offline_token=true&service=registry.docker.io: 401 Unauthorized
则需要配置容器运行时的HTTP传输。如果是docker,只需要在/etc/docker/daemon.json中增加insecure-registries并配置Harbor地址,然后重启docker服务即可。Containerd则需要修改/etc/containerd/config.toml中的多项配置。
# 备份containerd配置文件
[root@k8s-master1 jenkins]# cp /etc/containerd/config.toml /etc/containerd/config.toml.bak
# 修改containerd配置文件
[root@k8s-master1 jenkins]# vi /etc/containerd/config.toml
...
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.124.f".tls]
insecure_skip_verify = true # 跳过TLS认证
[plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.124.f".auth]
username = "admin" # 配置Harbor登陆用户和密码
password = "XXXXXX"
[plugins."io.containerd.grpc.v1.cri".registry.headers]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.124.f"]
endpoint = ["http://192.168.124.f"] # 配置Harbor访问地址
...
# 重启containerd
[root@k8s-master1 jenkins]# systemctl restart containerd
登录后重新推送即可(要加--insecure-registry):
[root@k8s-master1 jenkins]# nerdctl login http://192.168.124.f --insecure-registry
[root@k8s-master1 jenkins]# nerdctl push 192.168.124.f/library/jenkins-slave-jdk:1.8 --insecure-registry
☕️参考:https://goharbor.io/docs/2.0.0/install-config/run-installer-script/#connect-http
点击New Item输入名称java-demo,选中Pipeline再点击OK确认。

创建完成后,在java-demo → \rightarrow →Configure → \rightarrow →Advanced Project Options → \rightarrow →Pipeline中选择“Pipeline Script”。
将下面的测试脚本粘贴进去并保存。
pipeline {
agent {
kubernetes {
label "jenkins-slave"
yaml '''
apiVersion: v1
kind: Pod
metadata:
name: jenkins-slave
spec:
containers:
- name: jnlp
image: "192.168.124.f/library/jenkins-slave-jdk:1.8"
'''
}
}
stages {
stage('Main'){
steps {
sh 'hostname'
}
}
}
}
保存Pipeline脚本后,在新建项目中点击Build Now,然后在Build History中查看Console Output日志,直到输出Build成功的信息。
可以通过kubectl get pods命令检查k8s集群中是否会自动创建和销毁jenkins-slave Pod。
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty
我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions
前置步骤我们都操作完了,这篇开始介绍jenkins的集成。话不多说,看操作1、登录进入jenkins后会让你选择安装插件,选择第一个默认的就行。安装完成后设置账号密码,重新登录。2、配置JDK和Git都需要执行路径,所以需要先把执行路径找到,先进入服务器的docker容器,2.1JDK的路径root@69eef9ee86cf:/usr/bin#echo$JAVA_HOME/usr/local/openjdk-82.2Git的路径root@69eef9ee86cf:/#whichgit/usr/bin/git3、先配置JDK和Git。点击:ManageJenkins>>GlobalToolCon
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功