2828 字
14 分钟
KubeSphere实现前端CI和CD

背景#

在大型前端项目中,将应用部署到多台机器是一个常见的需求。这样做主要有以下几个原因:

  1. 高可用性:当某台服务器出现故障时,其他服务器仍然可以正常提供服务。
  2. 负载均衡:将用户请求分散到多台服务器上,提高系统整体的并发处理能力,优化用户访问体验。

使用Kubernetes(俗称k8s)对多台机器进行集群化管理是主流的选择,而KubeSphere是一款优秀的Kubernetes可视化平台。

本文选择在单台国内服务器上快速部署 Kubernetes v1.31.0 和 KubeSphere v4.1,并实现前端项目CI/CD的各个流程,适合快速入门。 参考官方文档

准备服务器#

TIP

16G的云服务器很贵,年付的方式动辄几千块。如果是出于学习目的,推荐使用腾讯云竞价实例,按量付费,价格极低,不使用时可以关机不计费😄。

  1. 公网IP是必须的
  2. 推荐使用16G内存的服务器,否则安装KubeSphere可能会失败。
  3. 安装Linux系统,我使用的是Ubuntu
  4. 使用root账号登录,这是必须的,否则有些流程会安装失败
WARNING

腾讯云默认创建主机名称是VM-xxx,存在大写字母,创建Kubernetes集群会失败,所以需要修改主机名称

  1. 修改主机名称
sudo hostnamectl set-hostname 新主机名称
  1. 编辑 /etc/hosts 文件以更新主机名映射 alt text
  2. 重启服务器
reboot

创建Kubernetes 集群#

设置下载区域#

export KKZONE=cn
WARNING

设置变量只在当前登录账号生效,下面的apt install./kk create cluster命令必须用root账号执行。

如果当前登录账号账号不是root账号,执行sudo apt installsudo ./kk create cluster获取到的KKZONE环境变量就不是cn,安装速度就会很慢。

安装KubeKey#

# 会生成 KubeKey 二进制文件 kk
curl -sfL https://get-kk.kubesphere.io | sh -

安装依赖项#

apt install socat conntrack -y

创建一个 Kubernetes 集群#

./kk create cluster --with-local-storage  --with-kubernetes v1.31.0 --container-manager containerd  -y
TIP

以上命令会使用内置的Docker运行时,所以主机不用预先安装Docker了

安装 KubeSphere#

安装Helm#

参考官网,使用Snap进行安装:

snap install helm --classic

通过 helm 安装 KubeSphere 的核心组件#

helm upgrade --install -n kubesphere-system --create-namespace ks-core https://charts.kubesphere.com.cn/main/ks-core-1.1.3.tgz --debug --wait   --set global.imageRegistry=swr.cn-southwest-2.myhuaweicloud.com/ks --set extension.imageRegistry=swr.cn-southwest-2.myhuaweicloud.com/ks
WARNING

以上命令设置了国内的源和镜像拉取地址,适合国内服务器使用

安装完成后会出现以下提示,稍等一会之后,访问http://公网IP:30880 页面,默认账号:admin,默认密码:P@88w0rd 。

NOTES:
Thank you for choosing KubeSphere Helm Chart.

Please be patient and wait for several seconds for the KubeSphere deployment to complete.
...

如果访问不了,执行以下命令,如果存在pod的STATUS不是Running状态,就继续等待。

kubectl get pods -n kubesphere-system

alt text

使用KubeSphere#

关于集群#

集群配置比较麻烦,这里直接使用已创建的host主集群,生产环境推荐创建一个新集群再使用。

DevOps扩展#

使用CI/CD功能依赖DevOps扩展,所以首先需要安装这个插件。 alt text 扩展中心搜索Devops,点击搜索结果。 alt text 点击安装,点击下一步alt text 点击开始安装。安装完成之后,点击下一步 alt text 集群选择选择host集群,点击下一步确认,弹窗会关闭,在后台安装集群 Agent

需要等待一段时间,可以在以下位置查看集群 Agent安装日志,安装完成这个这个三角形会消失。 alt text

企业空间#

在首页点击企业空间 alt text 再点击创建,输入名称fe-workspace,点击下一步alt text 可用集群选择host集群。 alt text 点击确认创建企业空间。

点击进入创建的企业空间页面,只需要关注Devops项目项目 alt text

项目#

项目相当于是一个命名空间,项目下可以创建应用,创建服务的时候可以同步创建关联的工作负载,工作负载就是前端构建产物的运行容器。

创建项目#

在项目模块,点击创建,输入名称demo-project,点击确定alt text 点击进入创建的项目页面,点开应用负载菜单栏,只需要关注服务工作负载alt text

创建服务#

企业空间页面,点击服务->创建,我们要部署的前端项目构建物只是静态文件,所以选择无状态服务alt text 输入服务名称demo-service版本保留默认值 v1 即可,点击下一步alt text 将弹窗向上滚动,点击添加容器alt text 容器组副本数量可以设置运行的容器数量,实现负载均衡。

运行服务需要选择镜像,但是我们的项目还没有构建镜像,这里先选一个nginx镜像用于跑负载,在后续的流水线中将镜像替换。 在镜像搜索框输入:docker.1ms.run/nginx:alpine-perl,回车搜索,在搜索结果列表中选择对应的版本,注意这里输入的是国内镜像,Dockerhub的镜像是找不到的。

容器名称输入:demo-container alt text

向下滚动到可用配额,可以根据实际情况设置分配的资源,这里不做限制。

点击使用默认镜像端口,会自动填入容器的nginx端口和容器对外暴露端口,都是80端口,后续我们配置构建镜像端口要保持一致。 alt text 点击下一步,进入存储设置,这里无需修改,点击下一步

勾选外部访问,选择访问模式为NodePort,将为对外暴露一个可以通过公网ip访问的服务端口alt text 点击创建

点击服务模块,可以看到创建的服务对外暴露的端口 alt text 此时可以通过http://公网ip:服务外部访问端口访问页面了,可以看到nginx信息页。 alt text 点击工作负载模块,注意到创建的负载名称是demo-service-v1 alt text

创建Devops#

企业空间页面,点击Devops->创建,输入名称demo-devops,点击确定。 点击进入创建的Devops页面,只需要关注凭证代码仓库流水线

凭证#

配置kubeconfig凭证#

kubeconfig凭证用于为集群执行kubectl命令提供凭证,添加方式

  1. 点击凭证->创建
  2. 类型选择kubeconfig内容会自动填充,不用修改
  3. 名称输入:kubeconfig
  4. 点击确定 alt text

配置镜像仓库凭证#

添加镜像仓库凭证,为登录镜像仓库平台提供用户名和密码

  1. 点击凭证->创建 2.类型选择用户名和密码, 3.名称输入:harbor
  2. 输入镜像仓库的用户名密码
  3. 点击确定 alt text

创建前端项目#

使用npm create vite创建一个vue项目,添加构建所属配置文件,并提交到git仓库中,为了方便访问,这里选择提交到gitee并设置并设置的公开项目。可以参考这个gitee项目

deploy目录为构建配置文件,包含三个文件

Jenkinsfile文件#

执行jenkins流水线的声明文件,在构建镜像使用到了Dockefile文件

pipeline {
  agent {
    kubernetes {
      // 继承KubeSphere自带的nodejs容器
      inheritFrom 'nodejs base'
      containerTemplate {
        // 容器名称,提供给下面的stage使用
        name 'nodejs'
        // 使用国内可以访问的镜像指定nodejs版本
        image 'docker.1ms.run/node:18-alpine'
      }
    }
  }

  // 环境变量
  environment {
    // 镜像仓库域名,不可删除
    REGISTRY = 'harbor.nick-h.cn'
    // 镜像仓库名称,不可删除
    DOCKERHUB_NAMESPACE = 'qq742037091'
    // 镜像应用名称,不可删除
    APP_NAME = 'demo'
    // 使用环境变量组装镜像名称,BUILD_NUMBER为流水线编号
    DOCKER_IMAGE = "${REGISTRY}/${DOCKERHUB_NAMESPACE}/${APP_NAME}:snapshot-${BUILD_NUMBER}"
    // 项目名称
    DEPLOYMENT_NAMESPACE = 'demo-project'
    // 工作负载名称
    DEPLOYMENT_NAME = 'demo-service-v1'
    // 容器名称
    CONTAINER_NAME = 'demo-container'
  }

  stages {
    // 拉取代码
    stage('Clone repository') {
      steps {
          checkout(scm)
      }
    }

    // 安装依赖
    stage('Run npm install') {
      steps {
        // 使用agent中定义的的nodejs容器
        container('nodejs') {
          // 使用国内npm源,加速安装
          sh 'npm config set registry https://registry.npmmirror.com'
          sh 'npm install'
        }

      }
    }

    // 生产构建文件
    stage('Run npm build') {
      steps {
        // 使用agent中定义的的nodejs容器
        container('nodejs') {
          sh 'npm run build'
        }
      }
    }

    // 构建镜像并推送到镜像参考
    stage('Run docker build') {
      agent none
      steps {
        // 使用kubesphere自带的base镜像,可以执行docker命令
        container('base') {
          sh 'docker build -f /deploy/Dockerfile -t $DOCKER_IMAGE .'
          // 使用私有的镜像仓库凭证,名称:harbor
          withCredentials([usernamePassword(credentialsId: 'harbor', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
            // 登录镜像仓库
            sh 'echo "$DOCKER_PASSWORD"|docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
            // 推送镜像
            sh 'docker push $DOCKER_IMAGE'
          }
        }
      }
    }

    // 部署到Kubernetes
    stage('Deploy to Kubernetes') {
        steps {
            script {
                // 使用配置好的Kubernetes凭证,名称:kubeconfig
                withCredentials([kubeconfigFile(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
                  // 使用kubesphere自带的base镜像,可以执行kubectl命令
                  container('base') {
                    // 使用kubectl命令,更新工作负载镜像名称,注意这里每次构建的镜像名称都不一样
                    sh """
                      kubectl set image deployment/${DEPLOYMENT_NAME} ${CONTAINER_NAME}=${DOCKER_IMAGE} -n ${DEPLOYMENT_NAMESPACE}
                    """
                    // 获取部署结果
                    sh """
                      kubectl rollout status deployment/${DEPLOYMENT_NAME} -n ${DEPLOYMENT_NAMESPACE}
                    """
                  }
                }
            }
        }
    }
  }
}

Dockefile文件#

构建镜像的配置文件,使用到nignx配置文件

# 拉取国内的nginx镜像
FROM docker.1ms.run/nginx:alpine-perl
# 暴露80端口
EXPOSE 80
# 复制构建文件到nginx http根目录
COPY ./dist /usr/share/nginx/html
# 删除默认nginx配置
RUN rm /etc/nginx/conf.d/default.conf
# 复制自定义nginx配置
COPY ./deploy/nginx.conf /etc/nginx/conf.d/

ningx.conf 文件#

容器内nginx的配置文件,会替换掉默认的配置文件

server {
    listen       80; # 监听80端口
    server_name  localhost; # 匹配localhost域名

    root /usr/share/nginx/html;  # 设置ningx http根目录,如果前端项目设置了baseUrl,需要在路径后面补充
    index index.html index.htm;  # 设置访问路径最后的index.html/index.htm可缺省

    location / {
        # 设置html文件不缓存
        if ($request_filename ~ .*.(html|htm)$) {
          expires -1s;
        }
        # 设置js、css、图片、字体缓存30天
        if ($request_filename ~ .*.(js|css|jpe?g|png|gif)$) {
          expires 30d;
        }
        try_files $uri $uri/ =404;  # 未匹配到文件,跳转到404文件
    }
}

添加代码仓库#

点击代码仓库->创建,输入名称demo-repo alt text 点击选择代码仓库,切换git页签 alt text 输入git仓库地址,由于使用的是公开仓库,不用输入凭证。点击√号,再点击确定,完成添加。

添加流水线#

点击代码仓库->创建,输入名称demo-pipeline,流水线类型选择多分支流水线,再选择已添加的代码仓库,点击下一步。 alt text 勾选正则过滤,设定构建流水线绑定的git分支。

脚本路径设置为:deploy/Jenkinsfile

勾选扫描触发器,根据需要选择定时扫描间隔,在检查到git分支有更新时自动运行流水线alt text

点击创建

alt text 如果配置没问题,流水线已经跑起来了。如果没有跑起来可以查看扫描日志。

查看流水线日志#

点击运行中的流水线,查看运行日志。 alt text

如果流水线运行成功,访问http://公网ip:服务外部访问端口

可以看到页面已经更新为前端项目首页了🎉🎉🎉。 alt text

KubeSphere实现前端CI和CD
https://www.nick-h.cn/blog/posts/kubesphere实现前端ci和cd/
作者
Nick
发布于
2025-02-23
许可协议
CC BY-NC-SA 4.0