摘要:使用Jenkins对项目代码进行持续集成和持续发布,代码提交后,通过Gitlab Trigger触发Jenkins任务,Jenkins完成项目构建打包,image制作,最后部署新的版本的k8s集群上。

一、在Kubernetes上快速部署Jenkins

1. Helm安装Jenkins

社区提供的charts https://github.com/jenkinsci/helm-charts
截止2020年10月4号,最新的chart tag是2.8.1

自定义配置参数

  1. master:
  2. resources:
  3. requests:
  4. cpu: "4"
  5. memory: "8Gi"
  6. limits:
  7. cpu: "4"
  8. memory: "8Gi"
  9. ingress:
  10. enabled: true
  11. apiVersion: "networking.k8s.io/v1beta1"
  12. annotations:
  13. kubernetes.io/ingress.class: nginx
  14. kubernetes.io/tls-acme: "true"
  15. path: "/"
  16. hostName: jenkins2.3incloud.com
  17. tls:
  18. - secretName: tls-3incloudcom
  19. hosts:
  20. - jenkins2.3incloud.com
  21. prometheus:
  22. enabled: true
  23. persistence:
  24. size: 80Gi
  25. agent:
  26. image: "harbor.3incloud.com/jenkins/jnlp"
  27. resources:
  28. requests:
  29. cpu: "1"
  30. memory: "1024Mi"
  31. limits:
  32. cpu: "1"
  33. memory: "1024Mi"
  34. volumes:
  35. - type: HostPath
  36. hostPath: /var/run/docker.sock
  37. mountPath: /var/run/docker.sock
  38. command: ""
  39. args: ""

其中agent的镜像来自于下面的自定义Jnlp

二、自定义Jnlp

自定义agent的镜像目的是为了让agent可以操作k8s的API,在完成CI任务后,就可以操作k8s完成CD过程。

做法是在原社区镜像的基础上,安装kubectl,helm和docker工具,下述Dockfile示例。

FROM jenkins/inbound-agent:4.3-4
MAINTAINER David Tesar <david.tesar@microsoft.com>

ARG VCS_REF
ARG BUILD_DATE

# Metadata
LABEL org.label-schema.vcs-ref=$VCS_REF \
      org.label-schema.vcs-url="https://github.com/dtzar/jnlp-slave-helm" \
      org.label-schema.build-date=$BUILD_DATE \
      org.label-schema.docker.dockerfile="/Dockerfile"

USER root

# Note: Latest version of kubectl may be found at:
# https://aur.archlinux.org/packages/kubectl-bin/
ENV KUBE_LATEST_VERSION="v1.18.6"
# Note: Latest version of helm may be found at:
# https://github.com/kubernetes/helm/releases
ENV HELM_VERSION="v3.3.1"
# Note: Latest version of docker may be found at:
# https://get.docker.com/builds
ENV DOCKER_VERSION="18.09.9"

RUN apt-get update && apt-get install -y --no-install-recommends \
    # Install Kubectl
    && curl -L https://storage.googleapis.com/kubernetes-release/release/${KUBE_LATEST_VERSION}/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl \
    && chmod +x /usr/local/bin/kubectl \
    # Install Helm
    && curl -L https://get.helm.sh/helm-v3.3.4-linux-amd64.tar.gz -o /tmp/helm.tar.gz \
    && tar -zxvf /tmp/helm.tar.gz -C /tmp \
    && cp /tmp/linux-amd64/helm /usr/local/bin/helm \
    # Install Docker
    && curl -L https://download.docker.com/linux/static/stable/x86_64/docker-19.03.12.tgz -o /tmp/docker-19.03.12.tgz \
    && tar --strip-components=1 -xvzf /tmp/docker-19.03.12.tgz -C /usr/local/bin \
    && chmod a+x /usr/local/bin/dockerd \
    # Cleanup uncessary files
    && apt-get clean \
    && rm -rf /tmp/* ~/*.tgz

三、Jenkins集成Gitlab

安装完成后,登录Jenkins,安装Gitlab、NodeJS和DockerPipline插件。

Jenkins配置

1. 在系统配置中设置Gitlab

image.png

2. 在Credentials中增加一组密钥,过程省略。

  • harbor用来管理镜像
  • 采用https pull代码

image.png

3. 在全局工具中配置NodeJS

image.png

4. 在k8s中设置Agent使用的ServiceAccount权限

cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: default
  namespace: jenkins
EOF

上述示例是将命名空间为jenkins的默认服务账号关联到集群管理员。Jenkins完成项目的部署和更新需要比较多的权限,这里采用简化版的操作,一刀切了,给它最大权限。

5. 配置image pull secret

kubectl create secret docker-registry harborsecret \
--docker-server='<registry server>' \
--docker-username='<username>' \
--docker-password='<password>' \
--docker-email='<email>' \
-n <namespace>

四、使用Pipline部署Node应用

1. 在项目根目录添加Jenkinsfile文件

Jenkinsfile示例

pipeline {
    agent any
    environment {
        ENV_NAME = "alpha"
    }
    parameters {
        choice(name: 'DEPLOY_ACTION',choices:['TEST', 'PRODUCT', 'FALSE'], description:'Deploy To Kubernetes Cluster')
    }
    tools {
        nodejs "node"
    }
    stages {
        stage('Build') {
            when {
                expression { BRANCH_NAME ==~ /test/ }
            }
            steps {
                echo '3. Build Stage'
                script {
                    if (params.DEPLOY_ACTION == 'PRODUCT') {
                        ENV_NAME = 'prod'
                    }
                }
                sh "npm install --registry=https://registry.npm.taobao.org && npm run build"
                sh "docker build . -t harbor.3incloud.com/shiia/shiia-app-api:${build_tag}"
            }
        }
        stage('Push') {
            when {
                expression { BRANCH_NAME ==~ /test/ }
            }
            steps {
                echo '4. Push Stage'
                withDockerRegistry([credentialsId: 'harbor-wuyuexin', url: "https://harbor.3incloud.com"]) {
                    sh "docker push harbor.3incloud.com/shiia/shiia-app-api:${build_tag}"
                }
             }
        }
        stage('DeployToTest') {
            when {
                expression { return params.DEPLOY_ACTION == 'TEST'}
                expression { BRANCH_NAME ==~ /test/ }
            }
            steps {
                echo '5. Deploy Stage'
                sh "ls -la"
                sh "helm upgrade test-shiia-app-api helm-charts/shiia-platform-api/ --namespace test-shiia-app --reuse-values --set-string image.tag=${build_tag}"
            }
        }
    }
}

2. Jenkins创建新的项目

新建多分支类型Pipline类型项目,过程略过。

五、快速发布与更新

为了简化部署,使用Helm对软件安装包进行管理,这样大大简化了部署流程以及版本的更新。

在完成一系列的配置操作后,整个过程就结束啦。整个过程的复杂的地方主要包含

  • Jenkins Agent自定义镜像制作
  • Jenkins 一系列插件的安装与配置
  • 部署包chart的编写
  • Jenkinsfile的编写

image.png