k8s + jenkins + kubeSphere devops入门

k8s + jenkins + kubeSphere部署应用

参考:Jenkins+k8s实现自动化部署

这里的k8s有两层意义,第一层就是把jenkins的agent部署到k8s里面,以实现各种一次性的独立的构建环境,第二层意义是把项目代码部署到k8s里面

说明:以下的操作是在win11专业版上进行的,安装wsl2,在win上面用linux,jenkins直接安装在linux里面

必备环境

  • 安装wsl2,选ubuntu, 后续操作都是在ubuntu中进行
  • 安装jenkins
  • 安装docker engine和docker-compose
  • 安装minikube
  • 安装kubectl
  • 安装harbor

wsl2安装ubuntu

如何使用 WSL 在 Windows 上安装 Linux

shell 复制代码
# 会自动安装ubuntu
wsl --install

安装jenkins

Jenkins Debian Packages 大概步骤就是先下载个啥.asc文件,然后转换成jenkins.list,再然后更新仓库列表,然后就能找到jenkins官方下载地址下载安装

安装docker engine

安装docker engine的ubuntu版本

安装好后用docker info,测试是否ok,第一次engine可能启动比较慢会导致docker info提示连不上,可以稍等会儿,后续每次docker engine会跟随系统自动启动

如果按上面的链接操作安装,则直接安装了docker compose plugin,就可以通过docker compose执行原先的docker-compose命令,或者单独安装一个docker-compose

独立安装docker-compose

ps: sudo docker run hello-world可能镜像会下载不了,需要魔法

如何设置非安全的Docker镜像仓库

json 复制代码
// 这一步是为了后续能以http的形式访问本地harbor
// 修改下 /etc/docker/daemon.json
// 添加这么一段,文件如果不存在就新建一个
 {
   "insecure-registries":["你的ubuntu ip"]
 }

安装minikube

安装minikube

shell 复制代码
# 安装好后执行,这一步依赖docker,会下载相关镜像生成一个minikube container
minikube start --drvier=docker --insecure-registry=linux的ip地址

安装kubectl

在 Linux 系统中安装并设置 kubectl

安装harbor

harbor安装参考

这个安装没有参考官方,感觉官方的安装写的贼复杂,harbor安装依赖docker和docker-compose

shell 复制代码
# 从github下载最新的安装包,包里面有相关docker镜像,几百M,下载估计比较慢
# 1. liunx下载命令,或者用win下载,然后拷贝到linux, 所有版本列表https://github.com/goharbor/harbor/releases
wget https://github.com/goharbor/harbor/releases/download/v2.7.4/harbor-offline-installer-v2.7.4.tgz

# 2. 解压,并修改配置文件
tar zxf harbor-offline-installer-v2.7.4.tgz

# 默认有个harbor.yml.tmpl,直接从这个文件复制下,然后修改harbor.yml
cp harbor.yml.tmpl harbor.yml

harbor.yml的部分

shell 复制代码
# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: 172.22.109.126 # 地址就按上面提示的用ubuntu的ip,可以通过ifconfig,找到eth0开头的那一段,就是ubuntu的ip

# http related config
http:
  # port for http, default is 80. If https enabled, this port will redirect to https port
  port: 80

# https相关的都注释掉,这个搞起来麻烦,当然这一块简单了,后面docker和minikube都需要特别处理下这个问题
# https related config
# https:
#   # https port for harbor, default is 443
#   port: 443
#   # The path of cert and key files for nginx
#   certificate: /root/certs/reg.westos.org.crt
#   private_key: /your/private/key/path
shell 复制代码
# 3. 进入解压后的harbor目录
./prepare # 做一些准备工作

# 取出里面的镜像,创建container,这一步可能遇到permission denied,就是没权限,那可以加上 sudo ./install.sh
# 我用的就是 sudo ./install.sh,但又碰上找不到/root/.docker/docker-desktop/docker.sock的问题,可能是因为我先装过win版的docker desktop导致的
# 后面用了软连接处理的 ln s /var/run/docker.sock /root/.docker/docker-desktop/docker.sock
./install.sh 

# 浏览器访问
# 直接打开localhost就行,默认是80端口

具体步骤

  • 进入wsl2
  • 启动minikube
  • 启动harbor
  • 启动jenkins,访问jenkins的web控制台,安装k8s的各种插件
  • 构建集成kubectl和使用root用户的jenkins agent镜像
  • 编写k8s的deployment.yml文件,编写Jenkinsfile,编写Dockerfile
  • 创建pipline项目,填写项目信息,流水线选择pipline script from scm,填入信息,保存,执行构建,构建成功后用minikube service serviceName暴露服务,用浏览器查看

进入wsl2

可以搜索wsl,或者ubuntu就可以进入

启动minikube

shell 复制代码
# 安装好后执行,这一步依赖docker,会下载相关镜像生成一个minikube container
# insecure的意思是允许以http的形式访问本地harbor,前面harbor不是图简单直接把https注释了吗
minikube start --driver=docker --insecure-registry=linux的ip地址

# 启动k8s 控制台,便捷操作deployment, pod的查看删除操作
nohup minikube dashboard &
tail nohup.out # 打开日志,ctrl + 点击对应链接可在浏览器打开对应的dashboard

启动harbor

再执行一遍前面的harbor安装步骤涉及的install.sh文件即可,就能启动了,目前没整明白为啥harbor没有在系统重启后随docker自动启动

访问localhost,输入默认用户名 "admin" 默认密码 "Harbor12345",创建仓库

启动jenkins并访问jenkins的web控制台

shell 复制代码
# 启动
nohup jenkins &

# 从log中找到jenkins初始化需要的字符串
tail nohup.out

访问localhost:8080, 进入后安装k8s相关插件

  • Kubernetes plugin:用于实现jenkins agent的k8s部署 参考插件官网
  • Kubernetes :: Pipeline :: DevOps Steps 作用没搞懂
  • Kubernetes CLI Plugin:用于实现kubectl连接远程k8s cluster,提供用户名密码和远程k8s cluster给它,就可以安装kubectl,然后操作远程k8s cluster了

添加安全凭证,后续的Jenkinsfile编写需要用到这些凭证,系统管理 -> 凭据管理 -> 添加凭据

  • gitee: 用于git拉代码,选username with password,id填入gitee,可以任意起名字,后续编写Jenkinsfile指定这个名字即可
  • harbor:用于登录harbor,选username with password,id填入harbor
  • sa-secret: 用于访问k8s cluster,选择secret text,填入token,id设置为sa-secret,token按下面的步骤获取
  1. 创建用于访问k8s cluster的凭据
shell 复制代码
# 创建serviceAccount,这一步没怎么研究,就跟着网上的走
# 创建一个名为jenkins-robot的sa
kubectl create serviceaccount jenkins-sa

# 绑定角色啥的,没太懂
kubectl create rolebinding jenkins-sa-binding --clusterrole=cluster-admin --serviceaccount=default:jenkins-sa
  1. 创建secret绑定到对应的serviceAccount
yaml 复制代码
apiVersion: v1
kind: Secret
metadata:
  name: sa-secret # 指定secret的名字
  annotations:
    kubernetes.io/service-account.name: "jenkins-sa" # 绑定到jenkins-sa这个serviceAccount上
type: kubernetes.io/service-account-token
  1. 查看找到secret对应的token并复制token
shell 复制代码
kubectl describe secret sa-secret
# 得到一大堆字符串,类似下面这种,复制其中token字段的值
#Name:         sa-secret
#Namespace:    default
#
#Type:  kubernetes.io/service-account-token
#
#Data
#====
#ca.crt:     1111 bytes
#extra:      4 bytes
#namespace:  7 bytes
#token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InNFNTdsTTBMSnUyQWNLNU4tLXl2S1Q0aDdzYm1USnFZWGtlbTRTdWhrZ00ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNhLXNlY3JldCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZTUyMTAyMDAtMGFhMS00Mjc2LWE4N2QtMjVhNTdkNjdlOTRkIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6ZGVmYXVsdCJ9.TrL5U-3GeYW5DORcG6Rk7CC2pGa0AO_pZ8O1Ia7vIKxiZq1STvQyewtJiBSUcpKPUmsTe60uWLR6_1MY3-7EESGx3G-XUIRtF9Bt5HGEnhfZn6-BGP0brXYQXhfMcssQdePYroO9N9N3LQnyMroCHyCFhamU_-gIKNgotLiE8xO-kA5v6FFgK3rzohex-qQyOEJRDoaIESvo-FlxDu2Ai8KXsTvd0wKTG1s-C5XtgUPczJuHUW8bHepuwimUsvtB4vI_XoygaeicOT_uajd9Hh5tVeX4pzl_vwSolrH-dVwEGjUCoEVp6-wDjs5ox0GEz4tFvQzIcL8pFbjPHuOibw

创建cloud,即指定连接哪个k8s集群

创建即可,后续的kubernetes plugin的podTemplate如果不指定cloud会自动使用这个(猜的)

系统管理 -> clouds -> new cloud,填入名称k8s,选择kubernetes,如果没有这个选项也许你还没安装kubernetes plugin

yaml 复制代码
# 1. Kubernetes 地址: 用下面的命令获取,取第一个
kubectl cluster-info

# 2. 勾选 "禁用 HTTPS 证书检查"

# 3. 凭据选择前面创建的sa-secret然后连接测试,通过了表示可以连接到k8s cluster,即后续的jenkins agent可以部署到k8s上

# 4.Jenkins 地址: 不填就会用jenkins系统配置里面的地址,填的话不要用localhost或者127,要用本地真实ip
#   Jenkins 通道不用填
# 保存即可

构建集成kubectl和使用root用户的jenkins agent镜像

构建自己的agent镜像,因为用默认镜像的话是使用不了kubectl命令的,而尝试挂载host中的kubectl又失败了,所以自己打包一个安装了kubectl的版本

Dockerfile 复制代码
# 这个版本应该是随意的,我写这个是前面使用过程中发现我安装的kubernets plugins自动用的这个版本,也可以用最新版吧
FROM jenkins/inbound-agent:3192.v713e3b_039fb_e-1
# 修改为root用户启动,这一步很重要,默认jenkins agent用的是jenkins用户启动,会导致访问不了主机的docker.sock
# 不过也可以配置 kubernets plugins的runAsUser参数, runAsUser: '0', 也表示用root用户启动
USER root

# 这一步kubectl的版本号,需要保持和host一致,可以通过 kubectl version查看版本
ARG KUBECTL_VERSION=1.28.4

# Install kubectl (same version of aws esk)
RUN curl -sLO https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl && \
    mv kubectl /usr/bin/kubectl && \
    chmod +x /usr/bin/kubectl

ENTRYPOINT ["/usr/local/bin/jenkins-agent"]
shell 复制代码
# 构建镜像并推送
docker build -t localhost/my-rep/agent1:latest

docker push localhost/my-rep/agent1:latest

编写Dockerfile,Jenkinsfile,k8s配置文件

先在gitee上创建个项目,然后用vue-cli进行下初始化,在新建个deploy目录,在里面创建deployment.yml, Dockerfile和Jenkinsfile放在根目录

Dockerfile

Dockerfile 复制代码
# 从docker hub下载nginx镜像,然后复制dist目录下的文件到/usr/share/nginx/html/,因为nginx启动后,主页默认在这个目录
FROM nginx:alpine
COPY dist/ /usr/share/nginx/html/

创建一个secret

shell 复制代码
kubectl create secret docker-registry my-docker-secret \
  --docker-username=admin \
  --docker-password=Harbor12345 \
  --docker-server=你的ubuntu ip

k8s deployment.yml

shell 复制代码
# 创建deployment,名称为nginx,使用镜像为IMAGE_PATH,这是个占位字符,后续在pipline中会用正则把它替换成真正的镜像地址
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: IMAGE_PATH
          ports:
            - containerPort: 80
      imagePullSecrets:
        - name: my-docker-secret # 指定一个前面创建的docker-registry类型的secret,用于拉取harbor镜像
---
# 创建一个service,用于暴露pod的80端口
apiVersion: v1 
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 80
  type: NodePort

Jenkinsfile

shell 复制代码
def HARBOR_URL = '你的ubuntu IP'
// podTemplate用法是kubernetes plugins提供的,也可以用声明式语法,都差不多,kubernetes plugins官网能看到各种用法
// 
podTemplate(volumes: [
        // 挂载主机的docker,然后可以使用docker命令,类似于win上的快捷方式,不过这一步要用前面自己构建的容器,否则默认的启动用户没有访问docker.sock的权限
        hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'), 
        hostPathVolume(mountPath: '/usr/bin/docker', hostPath: '/usr/bin/docker'),
        hostPathVolume(mountPath: '/home/jenkins/agent/.pnpm-store', hostPath: '/root/.local/share/pnpm/'), // 挂载pnpm的全局存储库,减小pnpm安装包的时间,这一步如果有问题也可以去除
        
    ], 
    // 或者配置 runAsUser: '0'也可以启用root用户
    // 配置容器信息,自己构建容器,加入了kubectl和使用root用户
    containers: [
        containerTemplate(
            name: "jnlp",
            image: "${HARBOR_URL}/my-rep/agent1:latest"
        ),
        containerTemplate(name: "nodejs", image: "node:18-alpine", command: 'sleep', args: '99d') // 要加上sleep命令,否则container启动后自动关闭,没搞懂为啥
    ]) {
    node(POD_LABEL) {
        
        // 拉取代码并打包
        stage("clone") {
           git credentialsId: 'gitee', url: 'https://gitee.com/xxx/test-jenkins.git'
           container("nodejs") {
                sh '''npm install -g pnpm@7 
                    pnpm i
                    pnpm build
                '''
            }
        }

        // 构建镜像
        stage("build") {
            echo "开始构建docker镜像"
            sh "docker build -t ${HARBOR_URL}/my-rep/nginx:${env.BUILD_NUMBER} ."
            echo "构建结束"
        }
        // 上传镜像到私有镜像库
        stage("publish") {
            // 获取harbor的用户命和密码
           withCredentials([usernamePassword(credentialsId: 'harbor', passwordVariable: 'HARBOR_SECRET_PSW', usernameVariable: 'HARBOR_SECRET_USR')]) {
                echo "开始推送镜像"
                sh "docker login -u ${HARBOR_SECRET_USR} -p ${HARBOR_SECRET_PSW} http://${HARBOR_URL}"
                sh "docker push ${HARBOR_URL}/my-rep/nginx:${env.BUILD_NUMBER}"
                echo "推送结束"
            }
        }
        // 进行k8s发布
        stage("deploy") {
            // withKubeConfig由kubernetes cli提供,用于访问k8s cluster
              // 这一步配置内网ip很重要
              // 这个serverUrl不是通过kubectl cluster-info得到的那个,那个是外部访问的ip,而这里因为agent是部署在k8s里面的,和k8s cluster在同一个内部网络,需要用内网地址
              // kubectl get services 得到下面的参数,取kubernetes这个ip加端口
              // kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP        23h
              // nginx-service   NodePort    10.108.227.72   <none>        80:30080/TCP   23h
             withKubeConfig(credentialsId: 'sa-secret', serverUrl: 'https://10.96.0.1:443') {
               // 进入deploy目录,因为我项目的配置文件都放在了deploy目录下
                dir('deploy') {
                    def image_name = "${HARBOR_URL}\/my-rep\/nginx:${env.BUILD_NUMBER}"
                    echo "替换image路径"
                    sh "sed -i 's/IMAGE_PATH/${image_name}/g' deployment.yml"
                    echo "部署app"
                    sh "kubectl apply -f deployment.yml"
                    echo "部署结束,可以通过执行minikube service nginx-service得到一个可访问的地址,driver是docker且是wsl或win环境,NodePort类型的service的IP并不能直接被访问到,所以minikube提供了service命令"
                    
                }
            }
        }
    }
}

一些重要概念

  • jenkins master: 类型于一台主机,可以直接在上面运行任务,官方建议把master设置为禁止执行任务,只做控制用
  • jenkins agent:类似于一个只干活的主机,上面会运行jenkins的一个agent.jar,然后与master连接,master给它分配任务。然后这个agent可以直接其他主机上创建,也可以由k8s帮忙创建,而如果是k8s创建,就需要kubernetes plugins,按最基本的配置的话,它会生成一个名称为jnlp的container,用于执行任务以及和master连接通信,所以如果自己完全写k8s的配置的话也要写一个name为jnlp的container,同时里面要包含agent.jar的功能,那么直接用agent官方镜像或者集成官方镜像即可

过程中遇到的坑

网络问题

有镜像下载不下来的情况;有连不上docker deamon的情况;minikube start下载镜像贼慢还有可能失败;有连不上k8s cluster的情况;有连不上jenkins master的情况

解决办法:魔法是必须的,不仅win要魔法,还得开个tun mode给wsl也来个魔法,其次最好有个队友一起搞,这样能知道一些网络问题是哪配置出错了还是就是网慢

linux权限问题

多次出现各种权限问题,最典型的报错 permission denies,这个推荐没有linux基础的花1h看看linux用户、用户组、文件权限相关的内容, 推荐鸟哥相关linux文章

使用者与群组

Linux文件权限概念

极重要!权限与命令间的关系:

KubeSphere介绍

kubeSphere就是比k8s dashboard功能更加丰富,同时它还有很多其他功能,比如集成了jenkins的pipeline,下文主要介绍怎么使用kubesphere的devops功能。kubesphere安装了devops后 会生成jenkins master Pod,当使用pipeline功能时,会自动创建jenkins agent Pod,当然也可以自定义agent

kubesphere安装及devops安装和使用

在k8s中安装kubesphere

参照官网安装,装好后怎么都登录不了,最后发现是k8s版本太高导致,其实官网有说明只支持到k8s指定版本,没仔细看,反而花了巨多时间搜索登录页面的报错

安装KubeSphere DevOps 系统

然后坑又来了,devops插件怎么都装不上,最后尝试安装2.1的kubesphere版本,devops总算ok了

降kubesphere版本过程中,又涉及helm降版本安装,镜像拉不下来,参考解决k8s helm安装tiller出现ImagePullBackOff,ErrImagePull错误解决了

然后就是创建devops项目,创建流水线。可以直接复制Jenkinsfile。甚至可以直接用浏览器访问内部的jenkins,默认的service是ks-jenkins,找到其暴露的端口号即可,登录后能看到,kubesphere只是把流水线配置直接放在了pipline里面。 那么用kubesphere作为devops的优势在哪呢,也许是它简化了jenkins的各种插件的复杂配置?

反正我最后是没有用kubesphere完成过构建,可能是版本太低了,前面手动写的Jenkinsfile放进去执行各种报错,最终放弃。

最后

以上都是一些最简单的入门,很多总结是自己根据实践猜测的,并没有深入原理,还有很多概念不清不楚,因此可能会有很多错误,还请自行甄别。写这个的目的只是为了让自己了解下CI的工具集,并不打算深入。

相关推荐
林太白14 分钟前
ofd文件
前端·后端
闲云一鹤17 分钟前
Git 焚决!一个绝招助你找回丢失的代码文件!
前端·git
小宇的天下18 分钟前
Calibre 3Dstack--每日一个命令day 6 [process和export layout](3-6)
java·前端·数据库
牛奔30 分钟前
docker compose up 命令,默认配置文件自动查找规则
java·spring cloud·docker·容器·eureka
工具罗某人30 分钟前
docker快速部署jenkins
java·docker·jenkins
学烹饪的小胡桃30 分钟前
WGCAT工单系统 v1.2.7 更新说明
linux·运维·服务器·网络·工单系统
BigBigHang31 分钟前
【docker】离线设备安装镜像
运维·docker·容器
冴羽31 分钟前
2025 年最火的前端项目出炉,No.1 易主!
前端·javascript·node.js
wordbaby32 分钟前
Flexbox 布局中的滚动失效问题:为什么需要 `min-h-0`?
前端·css
学好statistics和DS35 分钟前
Docker文件与本地文件,系统
运维·docker·容器