devops-发布vue前端项目

回到目录

将使用jenkins+k8s发布前端项目

1 环境准备

node环境

在部署jenkins的服务器上搭建node环境

node版本

# 1.拉取
https://nodejs.org/download/release/v20.4.0/node-v20.4.0-linux-x64.tar.gz

# 2.解压到/usr/local目录下
sudo tar xf v20.4.0.tar.gz -C /usr/local
#   重命名为node20
mv v20.4.0 node20

# 3.配置环境变量
vim /etc/profile
export PATH=$PATH:/usr/local/node20/bin
#   文件生效
source /etc/profile

# 4.软连接
sudo ln -s /usr/local/node20/bin/npm /usr/local/bin/
sudo ln -s /usr/local/node20/bin/node /usr/local/bin/

# 5.验证
node -v
npm -v

验证环境没有问题后,将文件移动到jenkins的目录下

因为是docker部署的jenkins,挂载目录是/usr/local/docker/docker-jenkins/data,所以必须将node环境移动到该目录下,jenkins才能加载到

mv node20 /usr/local/docker/docker-jenkins/data

jenkins中下载nodejs插件

插件中搜索 nodejs

devops-发布vue前端项目_第1张图片

安装完成后重启,再次进入

在全局工具配置中,找到nodejs

devops-发布vue前端项目_第2张图片

安装目录为docker中jenkins的node目录,可进入docker jinkens容器中查看

2 项目构建

前提:在gitlab中创建一个vue项目,并确保该项目在本地能正常运行

我的项目结构如下,需要添加Dockerfile和jenkinsfile以及deploy目录

devops-发布vue前端项目_第3张图片 

创建完成后编写jenkinsfile

pipeline{
    agent any


    environment {
    		//gitlab访问凭证
        GIT_CREDENTIAL_ID = 'gitlab-root'
        //gitlab地址
        GIT_REPO_URL = '10.1.9.23:28080'
        //gitlab分组
        GIT_GROUP = 'devops'
        //gitlab项目名称
        GIT_NAME = 'fitmentfront'
        //harbor凭证
        HARBOR_ID = 'harbor-admin'
        //harbor地址
        HARBOR_URL = '39.10.18.1:8858'
        //harbor项目
        HARBOR_REPO = 'repo'
        //发送delpoment.yml到k8s服务器上的地址
        K8S_FILE_PATH = '/opt/k8s/deployfile'
        //gitlab发送到服务器的目录
        GITLAB_DEPLOYMENT_FILE = 'deploy'
    }

     parameters {
				//git插件 分支参数
        gitParameter(
                branchFilter: '.*',
                defaultValue: "${env.BRANCH_NAME ?: 'main'}",
                name: 'BRANCH_NAME',
                type: 'PT_BRANCH',
		description: '请选择要发布的分支'
            )
            //git插件 标签参数
	gitParameter(
                branchFilter: '.*',
                defaultValue: "${env.TAG_NAME ?: 'v:1.0.0'}",
                name: 'TAG_NAME',
                type: 'PT_TAG',
		description: '请选择要发布的标签'
            )
    }


    stages{
       stage("基本信息输出"){
            steps{
                echo '选定待发布信息'
                echo "项目地址    ${GIT_REPO_URL}"
                echo "项目组      ${GIT_GROUP}"
                echo "项目名      ${GIT_NAME}"
                echo "分支        ${BRANCH_NAME}"
                echo "TAG        ${TAG_NAME}"
            }
        }

        stage('拉取gitlab代码') {
            steps {
            		//拉取gitlab代码,选择分支
                checkout scmGit(
                    branches: [
                        [name: env.BRANCH_NAME]
                    ],
                    extensions: [],
                    userRemoteConfigs: [
                        [
                            credentialsId: env.GIT_CREDENTIAL_ID,
                            url: "http://${env.GIT_REPO_URL}/${env.GIT_GROUP}/${env.GIT_NAME}.git"
                        ]
                    ]
                )
                echo '拉取gitlab代码  --SUCCESS'
            }
        }

        stage("编译"){
            steps{
                nodejs('node') {
                    // some block
                    sh '''
                       npm install --registry=https://registry.npmmirror.com
                       npm run build
                    '''
                }
            }
        }
        

         stage("构建镜像"){
            steps {
            		//docker制作镜像
            		//将maven打包的jar移动到docker目录下
            		//使用dockerfile进行构建镜像,镜像名称为 项目名:标签
                sh """
                    echo $PWD
                    docker build -t ${env.GIT_NAME}:${env.TAG_NAME} .
                """
                echo '通过docker制作镜像  --SUCCESS'
            }

        }

        stage('推送镜像到harbor') {
            steps {
            		//使用harbor凭证推送镜像
                withCredentials([
                    usernamePassword(
                        credentialsId: env.HARBOR_ID,
                        passwordVariable: 'DOCKER_PASSWORD',
                        usernameVariable: 'DOCKER_USERNAME'
                    )
                ]) {
                		//打标签为远程仓库标签
                		//登陆到harbor
                		//推送镜像
                    sh """
                        docker tag ${env.GIT_NAME}:${env.TAG_NAME} ${env.HARBOR_URL}/${env.HARBOR_REPO}/${env.GIT_NAME}:${env.TAG_NAME}
                        echo "\$DOCKER_PASSWORD" | docker login -u "\$DOCKER_USERNAME" -p "\$DOCKER_PASSWORD" ${env.HARBOR_URL}
                        docker push ${env.HARBOR_URL}/${env.HARBOR_REPO}/${env.GIT_NAME}:${env.TAG_NAME}
                    """
                }
                echo '推送镜像到harbor  --SUCCESS'
            }
        }

        stage('发送k8s部署yml文件至目标服务器') {
            steps {
                //请空文件夹下所有文件内容
                sh """
                    ssh [email protected] rm -rf $K8S_FILE_PATH/*
                """
            		//使用ssh插件 发送deploy目录下的部署yml文件到目标服务器
            		//须提前配置ssh免密登陆
                sshPublisher(
                    publishers: [
                        sshPublisherDesc(
                            configName: 'k8s',
                            transfers: [
                                sshTransfer(
                                    cleanRemote: false,
                                    excludes: '',
                                    execCommand: '',
                                    execTimeout: 120000,
                                    flatten: false,
                                    makeEmptyDirs: false,
                                    noDefaultExcludes: false,
                                    patternSeparator: '[, ]+',
                                    remoteDirectory: '',
                                    remoteDirectorySDF: false,
                                    removePrefix: '',
                                    sourceFiles: "${env.GITLAB_DEPLOYMENT_FILE}/*yaml"
                                )
                            ],
                            usePromotionTimestamp: false,
                            useWorkspaceInPromotion: false,
                            verbose: false
                        )
                    ]
                )
                echo '发送yml文件至目标服务器  --SUCCESS'
            }
        }

        stage('远程执行k8s部署yaml命令') {
            steps {
            		//替换发送过来的部署文件
            		//部署
                sh """
                    ssh [email protected] sed -i'' "s#REGISTRY#${env.HARBOR_URL}#" ${env.K8S_FILE_PATH}/${env.GITLAB_DEPLOYMENT_FILE}/deployment.yaml
                    ssh [email protected] sed -i'' "s#DOCKERHUB_NAMESPACE#${env.HARBOR_REPO}#" ${env.K8S_FILE_PATH}/${env.GITLAB_DEPLOYMENT_FILE}/deployment.yaml
                    ssh [email protected] sed -i'' "s#APP_NAME#${env.GIT_NAME}#" ${env.K8S_FILE_PATH}/${env.GITLAB_DEPLOYMENT_FILE}/deployment.yaml
                    ssh [email protected] sed -i'' "s#BUILD_NUMBER#${env.TAG_NAME}#" /${env.K8S_FILE_PATH}/${env.GITLAB_DEPLOYMENT_FILE}/deployment.yaml
                    ssh [email protected] kubectl apply -f ${env.K8S_FILE_PATH}/${env.GITLAB_DEPLOYMENT_FILE}/
                """
                echo '远程执行k8s部署yaml命令  --SUCCESS'
            }
        }

    }
}

 Dockerfile

FROM node:14-alpine AS build
WORKDIR /build/fitment
COPY . .
RUN npm install --registry=https://registry.npmmirror.com && npm run build

FROM nginx:1.22
WORKDIR /app/fitment
COPY --from=build /build/fitment/dist .
EXPOSE 80

deploy中的deployment.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: fitment
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: fitment-conf
  namespace: fitment
  labels:
    app: nginx-conf
data:
  nginx.conf: |
    server {
        listen  80;
        server_name localhost;

        location / {
            root /app/fitment;
            index index.html index.htm;
        }

        location /api/ {
            #设置请求头等,防止出现跨域问题
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://fitmentback.fitment/; #设置监控后端启动的端口

        }

        error_page 500 502 503 504 /50x.html;

        location = /50x.html {
            root    html;
        }
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: fitmet-ui
    component: fitment-devops
    tier: front
  name: fitmet-ui
  namespace: fitment
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  selector:
    matchLabels:
      app: fitmet-ui
      component: fitment-devops
      tier: front
  strategy:
    rollingUpdate:
      maxSurge: 100%
      maxUnavailable: 100%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: fitmet-ui
        component: fitment-devops
        tier: front
    spec:
      imagePullSecrets:
        - name: harbor-secret
      containers:
        - name: fitmet-ui
          image: REGISTRY/DOCKERHUB_NAMESPACE/APP_NAME:BUILD_NUMBER
          imagePullPolicy: Always
          ports:
            - containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 30
            timeoutSeconds: 5
            failureThreshold: 5
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 20
            timeoutSeconds: 5
            failureThreshold: 3
            periodSeconds: 10
          resources:
            limits:
              cpu: 300m
              memory: 600Mi
            requests:
              cpu: 100m
              memory: 100Mi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - name: nginx-conf
              mountPath: /etc/nginx/conf.d/
      volumes:
        - name: nginx-conf
          configMap:
            name: fitment-conf
            items:
            - key: nginx.conf
              path: nginx.conf   
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: fitmet-ui
    component: fitment-devops
  name: fitmet-ui
  namespace: fitment
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: fitmet-ui
    component: fitment-devops
    tier: front
  sessionAffinity: None
  type: NodePort
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fitment-ui-ingress
  namespace: fitment
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: fitment.fooleryang.cn # 域名配置,可以使用通配符 *
    http:
      paths: # 相当于 nginx 的 location 配置,可以配置多个
      - pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
        backend:
          service:
            name: fitmet-ui # 代理到哪个 service
            port:
              number: 80 # service 的端口
        path: /

3 jenkins创建项目

在vue项目的准备工作完成后【本地运行正常,各个文件准备完成、提交到gitlab中】,创建jenkins流水线项目

执行构建,然后停止【目的:拉取源码的jenkinsfile,得到参数化构建配置】

执行第一次构建后参数化配置即会出现

devops-发布vue前端项目_第4张图片

再次选择tag进行构建

devops-发布vue前端项目_第5张图片

 构建完成后,去k8s中查看相应pod,发现处于运行状态

[root@k8s-master k8s]# kubectl get all -n fitment
NAME                            READY   STATUS    RESTARTS   AGE
pod/fitmet-ui-76c68f444-thm74   1/1     Running   0          23m

NAME                TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/fitmet-ui   NodePort   10.106.206.48           80:30800/TCP   37m

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/fitmet-ui   1/1     1            1           37m

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/fitmet-ui-76c68f444   1         1         1       37m

访问

可以用配置的ingress进行访问,也可以使用nodeport进行访问

成功访问,说明发布成功

devops-发布vue前端项目_第6张图片

 

你可能感兴趣的:(kubernetes,devops,vue.js,kubernetes,jenkins,云原生,gitlab)