jenkins-5:参数化构建结合jenkinsfile对go服务进行容器化部署

2022-08-31 10:41:33 浏览数 (1)

需求:

因为不同的服务需要的资源不一样,如cpu,内存等,需要做一个通用模版,对这些差异化资源通过参数来进行定制。

目录:

(1).准备工作

1.jenkins安装时间戳插件

2.测试用的golang-demo

3.其他准备

(2).参数化构建

1.创建pipeline并定制参数

2.定义流水线

3.执行构建

(3).语法注意事项

(4).使用jenkinsfile的方式进行参数化构建

(5).参考资料

(1).准备工作

1.jenkins安装时间戳插件

image的tag使用时间戳,需要安装jenkins插件:build timestamp。

还需要在jenkins的系统配置中修改timestamp的格式(默认是utc格式,不符合image名称语法):

时间戳改为数字形式,精确到秒。

2.测试用的golang-demo

https://gitee.com/future-cicd/jenkins-kubernetes-golang-demo

3.其他准备

jenkins-3:使用jenkinsfile在kubernetes中创建jnlp完成一个简单构建

jenkins-2:使用pipeline在kubernetes创建jnlp完成第一个最简task构建并剖析

jenkins-1:kubernetes中部署的jenkins配置k8s集群连接

harbor-1:创建用户与项目并推送第一个本地镜像到harbor

(2).参数化构建

1.创建pipeline并定制参数

创建pipeline后进行参数化配置:

repo_url:https://gitee.com/future-cicd/jenkins-kubernetes-golang-demo.git

demo的仓库地址。

credentialsId:xxxxxx

这个其实不需要,因为demo是public的,如果是private的,你需要在jenkins里创建credentialsId,输入你的用户名密码。

branch_name:master

要拉取的分支。

k8s_namespace:demo

要部署在k8s中的namespace。

harbor_url:harbor-core.qianlixinzou.com:31600

image要推送到的镜像仓库私服地址。

harbor_group:devops

image存放在harbor的group。

k8s_requests_memory,k8s_requests_cpu,k8s_limits_memory,k8s_limits_cpu:对应k8s的requests, limit。

2.定义流水线

流水线内容:

备份在:

https://gitee.com/future-cicd/jenkins-kubernetes-golang-demo/blob/master/jenkinsfile-with-params-build

代码语言:javascript复制
def image_tag = "${BUILD_TIMESTAMP}"
def image_name = "${env.JOB_NAME}"
def app_name = "${env.JOB_NAME}"


def harbor_url = "${params.harbor_url}"




def k8s_yaml = """


---
apiVersion: v1
kind: Namespace
metadata:
  name: ${params.k8s_namespace}


---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${app_name}
  namespace: ${params.k8s_namespace}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ${app_name}
  template:
    metadata:
      name: ${app_name}
      labels:
        app: ${app_name}
    spec:
      volumes:
      - name: ${app_name}-logs
        hostPath:
          path: /app/logs/${app_name}
          type: DirectoryOrCreate
      containers:
      - name: ${app_name}
        env:
          - name: APP_NAME
            value: ${app_name}
          - name: TZ                       # 添加
            value: Asia/Shanghai      # 添加
        image: ${params.harbor_url}/${params.harbor_group}/${app_name}:${image_tag}
        imagePullPolicy: IfNotPresent
        volumeMounts:
          - name: ${app_name}-logs
            mountPath: /app/logs
        resources:
          requests:
            memory: "${params.k8s_requests_memory}"
            cpu: ${params.k8s_requests_cpu}
          limits:
            memory: "${params.k8s_limits_memory}"
            cpu: ${params.k8s_limits_cpu}
          limits:
        ports:
        - name: web
          containerPort: 8080
        startupProbe:
          httpGet:
            path: /helloworld
            port: 8080
          failureThreshold: 30
          periodSeconds: 60
        livenessProbe:
          failureThreshold: 6
          httpGet:
            path: /helloworld
            port: 8080
          initialDelaySeconds: 50
          periodSeconds: 5
          timeoutSeconds: 5
        readinessProbe:
          failureThreshold: 10
          httpGet:
            path: /helloworld
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 5
          timeoutSeconds: 5


---
apiVersion: v1
kind: Service
metadata:
  name: ${app_name}-web
  namespace: ${params.k8s_namespace}
spec:
  selector:
    app: ${app_name}
  type: ClusterIP
  ports:
  - name: tcp
    port: 80
    targetPort: 8080
    
"""


podTemplate(cloud: 'kubernetes',nodeSelector: 'jenkins-jnlp=yes',
    containers: [
        containerTemplate(
            name: 'container-go', 
            //设置go代理,否则有些依赖包无法下载。
            envVars: [
                envVar(key: 'GO111MODULE', value: 'on'), 
                envVar(key: 'GOPROXY', value: 'https://mirrors.aliyun.com/goproxy/'),
                envVar(key: 'CGO_ENABLED', value: 'p0'),
                envVar(key: 'GOOS', value: 'linux')
            ],
            image: harbor_url '/devops/jenkins-jnlp-golang:1.18', 
            ttyEnabled: true,
            command: 'cat'
        ),
        containerTemplate(
            name: 'container-docker',
            ttyEnabled: true,
            image: harbor_url '/devops/jenkins-jnlp-docker:19.03'
        ),
    ],
    //需要将docker和kubectl挂在到pod中这样才可以在pod中与k8s进行联通操作。
    volumes: [
        hostPathVolume(hostPath: '/run/docker.sock', mountPath: '/run/docker.sock'),
        hostPathVolume(hostPath: '/etc/docker', mountPath: '/etc/docker'),
        hostPathVolume(hostPath: '/root/.kube', mountPath: '/root/.kube'),
        hostPathVolume(hostPath: '/usr/bin/kubectl', mountPath: '/usr/bin/kubectl')
    ]
 )
 {
    node(POD_LABEL) {
        stage('stage-1.Clone') {
            // 从git仓库拉取代码
            checkout([
                $class: 'GitSCM', 
                branches: [
                    [name: "${params.branch_name}"]
                ],
                browser: [$class: 'GitLab', repoUrl: "${params.repo_url}"], 
                doGenerateSubmoduleConfigurations: false, 
                extensions: [], 
                submoduleCfg: [], 
                userRemoteConfigs: [
                    [url: "${params.repo_url}", credentialsId: "${params.credentialsId}"]
                ]
            ])
        }
        stage('stage-2.Test') {
        }
        stage('stage-3.Build') {
            container('container-go') {
                // 将go应用构建名为app的可执行二进制文件
                sh "go mod tidy"
                //必须加CGO_ENABLED=0,因为alpine缺少很多go程序依赖的lib库,不加会提示你app not found,你需要ldd app才能看到需要依赖的lib库。
                sh "CGO_ENABLED=0 go build -o app "
                
            }
            container('container-docker') {
                sh """
                    echo "FROM ${params.harbor_url}/devops/alpine-golang-common:0.1" > ./Dockerfile
                    echo "ADD ./app /app/3rd/" >> ./Dockerfile
                    cat ./Dockerfile
                    """
                sh "docker build ./ -t ${params.harbor_url}/${params.harbor_group}/${image_name}:${image_tag}"
            }
        }
        stage('stage-4.Push') {
           container('container-docker') {
               sh "docker push ${params.harbor_url}/${params.harbor_group}/${image_name}:${image_tag}"
           }
        }
        stage('stage-5.Deploy') {
            container('container-docker') {
                writeFile(file: "k8s_yaml.yaml", text: "${k8s_yaml}")
                sh "cat k8s_yaml.yaml"
                sh "kubectl apply -f k8s_yaml.yaml"
            }
        }
    }
}

3.执行构建

(3).语法注意事项

主要是流水线定义中的语法注意:

获取jenkins时间戳插件中的时间戳:

def image_tag = "${BUILD_TIMESTAMP}"

获取jenkins任务的隐藏变量的写法,如JOB_NAME:

def image_name = "${env.JOB_NAME}"

def app_name = "${env.JOB_NAME}"

获取参数化构建中定义的参数:

def harbor_url = "${params.harbor_url}"

将变量值写入磁盘文件:

writeFile(file: "k8s_yaml.yaml", text: "${k8s_yaml}")

(4).使用jenkinsfile的方式进行参数化构建

创建流水线job,从前边那个复制即可。

流水线定义选择:Pipeline script from SCM

配置完成后,执行构建。由于job_name起的名字太长,容器化时会报错:

这个不重要,可以自行修改,这里只是验证jenkinsfile中也是可以取到各种变量。

(5).参考资料

1.JenkinsPipeline语法概要

https://www.ssgeek.com/post/jenkinspipeline-yu-fa-gai-yao/#421-文件目录相关步骤

0 人点赞