基于 K8S 构建 Jenkins 微服务发布平台

实现汇总:

  1. 发布流程设计讲解
  2. 准备基础环境
    1. K8s环境(部署Ingress Controller,CoreDNS,Calico/Flannel)
    2. 部署代码版本仓库Gitlab
    3. 配置本地Git上传测试代码,创建项目到Gitlab
    4. 部署pinpoint 全链路监控系统(提前修改Dockerfile,打包镜像上传)
    5. 部署镜像仓库Harbor(开启helm仓库)
    6. master节点部署helm应用包管理器(配置本地helm仓库,上传helm包)
    7. 部署K8S 存储(nfs、ceph),master节点提供pv自动供给
    8. 部署MySQL集群(导入微服务数据库)
    9. 部署EFK日志采集(追加)
    10. 部署prometheus监控系统(追加)
  3. 在Kubernetes中部署Jenkins
  4. Jenkins Pipeline 及参数化构建
  5. Jenkins在K8S中动态创建代理
  6. 自定义构建Jenkins-Slave镜像
  7. 基于Kubernetes构建Jenkins CI系统
  8. Pipeline 集成 Helm 发布微服务项目

发布流程设计讲解

机器环境

当前环境部署主要是实现微服务自动发布和推送,具体实现的功能细节主要实现在下述几大软件上面。其实自动发布和推送有很多种方式,如有不足,请留言补充。

IP地址 主机名 服务配置
192.168.25.223 k8s-master01 Kubernetes-Master节点+Jenkins
192.168.25.225 k8s-node01 Kubernetes-Node节点
192.168.25.226 k8s-node02 Kubernetes-Node节点
192.168.25.227 gitlab-nfs Gitlab,NFS,Git
192.168.25.228 harbor harbor,mysql,docker,pinpoint

准备基础环境

K8s环境(部署Ingress Controller,CoreDNS,Calico/Flannel)

部署命令

单Master版:

ansible-playbook -i hosts single-master-deploy.yml -uroot -k

多Master版:

ansible-playbook -i hosts multi-master-deploy.yml -uroot -k

部署控制

如果安装某个阶段失败,可针对性测试.

例如:只运行部署插件

ansible-playbook -i hosts single-master-deploy.yml -uroot -k --tags addons

示例参考:https://github.com/ansible/ansible-examples


部署代码版本仓库Gitlab

部署docker

Uninstall old versions
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
SET UP THE REPOSITORY
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
INSTALL DOCKER ENGINE
$ sudo yum install docker-ce docker-ce-cli containerd.io -y
$ sudo systemctl start docker && sudo systemctl enable docker
$ sudo docker run hello-world

部署gitlab

docker run -d \
--name gitlab \
-p 8443:443 \
-p 9999:80 \
-p 9998:22 \
-v $PWD/config:/etc/gitlab \
-v $PWD/logs:/var/log/gitlab \
-v $PWD/data:/var/opt/gitlab \
-v /etc/localtime:/etc/localtime \
passzhang/gitlab-ce-zh:latest

访问地址:http://IP:9999

初次会先设置管理员密码 ,然后登陆,默认管理员用户名root,密码就是刚设置的。

配置本地Git上传测试代码,创建项目到Gitlab

https://github.com/passzhang/simple-microservice

代码分支说明:

  • dev1 交付代码

  • dev2 编写Dockerfile构建镜像

  • dev3 K8S资源编排

  • dev4 增加微服务链路监控

  • master 最终上线

拉取master分支,推送到私有代码仓库:

git clone https://github.com/PassZhang/simple-microservice.git

# cd 进入simple-microservice目录
# 修改.git/config文件,将地址上传地址配置成本地gitlab既可以
vim /root/simple-microservice/.git/config
...
[remote "origin"]
url = http://192.168.25.227:9999/root/simple-microservice.git
fetch = +refs/heads/*:refs/remotes/origin/*
... # 下载之后,还需修改连接数据库配置(xxx-service/src/main/resources/application-fat.yml),本次测试我将数据库地址修改成192.168.25.228::3306.
# 修改好数据库地址后,才可以上传文件。 cd microservice
git config --global user.email "passzhang@example.com"
git config --global user.name "passzhang"
git add .
git commit -m 'all'
git push origin master

部署pinpoint 全链路监控系统(提前修改Dockerfile,打包镜像上传)


部署镜像仓库Harbor(开启helm仓库)

安装docker与docker-compose

# wget http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
# yum install docker-ce -y
# systemctl start docker && systemctl enable docker
curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

2.2 解压离线包部署

# tar zxvf harbor-offline-installer-v1.9.1.tgz
# cd harbor
-----------
# vi harbor.yml
hostname: 192.168.25.228
http: 8088
-----------
# ./prepare
# ./install.sh --with-chartmuseum --with-clair
# docker-compose ps

--with-chartmuseum 参数表示启用Charts存储功能。

配置Docker可信任

由于habor未配置https,还需要在docker配置可信任。

# cat /etc/docker/daemon.json
{"registry-mirrors": ["http://f1361db2.m.daocloud.io"],
"insecure-registries": ["192.168.25.228:8088"]
}
# systemctl restart docker
#这边配置好仓库之后,也要保证K8S的master节点和docker节点都能同时连接上。需要修改dameon.json文件。

master节点部署helm应用包管理器(配置本地helm仓库,上传helm包)

安装Helm工具

# wget https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz
# tar zxvf helm-v3.0.0-linux-amd64.tar.gz
# mv linux-amd64/helm /usr/bin/

配置国内Chart仓库

# helm repo add stable http://mirror.azure.cn/kubernetes/charts
# helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
# helm repo list

安装push插件

# helm plugin install https://github.com/chartmuseum/helm-push

如果网络下载不了,也可以直接解压课件里包:

# tar zxvf helm-push_0.7.1_linux_amd64.tar.gz
# mkdir -p /root/.local/share/helm/plugins/helm-push
# chmod +x bin/*
# mv bin plugin.yaml /root/.local/share/helm/plugins/helm-push

添加repo

# helm repo add  --username admin --password Harbor12345 myrepo http://192.168.25.228:8088/chartrepo/ms

推送与安装Chart

# helm push ms-0.1.0.tgz --username=admin --password=Harbor12345 http://192.168.25.228:8088/chartrepo/ms
# helm install --username=admin --password=Harbor12345 --version 0.1.0 http://192.168.25.228:8088/chartrepo/library/ms

部署K8S 存储(nfs、ceph),master节点提供pv自动供给

先准备一台NFS服务器为K8S提供存储支持。

# yum install nfs-utils -y
# vi /etc/exports
/ifs/kubernetes * (rw,no_root_squash)
# mkdir -p /ifs/kubernetes
# systemctl start nfs
# systemctl enable nfs

并且要在每个Node上安装nfs-utils包,用于mount挂载时用。

由于K8S不支持NFS动态供给,还需要先安装上图中的nfs-client-provisioner插件:

具体配置文件如下:

[root@k8s-master1 nfs-storage-class]# tree
.
├── class.yaml
├── deployment.yaml
└── rbac.yaml 0 directories, 3 files

rbac.yaml

[root@k8s-master1 nfs-storage-class]# cat rbac.yaml
kind: ServiceAccount
apiVersion: v1
metadata:
name: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io

class.yaml

[root@k8s-master1 nfs-storage-class]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "true"

deployment.yaml

[root@k8s-master1 nfs-storage-class]# cat deployment.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: quay.io/external_storage/nfs-client-provisioner:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 192.168.25.227
- name: NFS_PATH
value: /ifs/kubernetes
volumes:
- name: nfs-client-root
nfs:
server: 192.168.25.227
path: /ifs/kubernetes # 部署时不要忘记将server地址修改成新的nfs地址。
# cd nfs-client
# vi deployment.yaml # 修改里面NFS地址和共享目录为你的
# kubectl apply -f .
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-df88f57df-bv8h7 1/1 Running 0 49m

部署MySQL集群(导入微服务数据库)

# yum install mariadb-server -y
# systemctl start mariadb.service
# mysqladmin -uroot password '123456'

或者docker创建

docker run -d --name db -p 3306:3306 -v /opt/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7 --character-set-server=utf8

最后将微服务数据库导入。

[root@cephnode03 db]# pwd
/root/simple-microservice/db
[root@cephnode03 db]# ls
order.sql product.sql stock.sql
[root@cephnode03 db]# mysql -uroot -p123456 <order.sql
[root@cephnode03 db]# mysql -uroot -p123456 <product.sql
[root@cephnode03 db]# mysql -uroot -p123456 <stock.sql # 配置好之后需要修改数据库授权
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.25.%' IDENTIFIED BY '123456';

部署EFK日志采集(追加)


部署prometheus监控系统(追加)


在Kubernetes中部署Jenkins

参考:https://github.com/jenkinsci/kubernetes-plugin/tree/fc40c869edfd9e3904a9a56b0f80c5a25e988fa1/src/main/kubernetes

当前我们直接在kubernetes中部署Jenkins程序,部署之前需要提前准备好存储,前面已经部署了nfs 存储,也可以使用其他存储方案,例如ceph等。接下来我们开始部署吧。

Jenkins yaml文件汇总

[root@k8s-master1 jenkins]# tree
.
├── deployment.yml
├── ingress.yml
├── rbac.yml
├── service-account.yml
└── service.yml 0 directories, 5 files

rbac.yml

[root@k8s-master1 jenkins]# cat rbac.yml
---
# 创建名为jenkins的ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins ---
# 创建名为jenkins的Role,授予允许管理API组的资源Pod
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: jenkins
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list","watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"] ---
# 将名为jenkins的Role绑定到名为jenkins的ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins

service-account.yml

[root@k8s-master1 jenkins]# cat service-account.yml
# In GKE need to get RBAC permissions first with
# kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin [--user=<user-name>|--group=<group-name>] ---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins ---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: jenkins
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list","watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"] ---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins

**ingress.yml **

[root@k8s-master1 jenkins]# cat ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: jenkins
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: 100m
spec:
rules:
- host: jenkins.test.com
http:
paths:
- path: /
backend:
serviceName: jenkins
servicePort: 80

service.yml

[root@k8s-master1 jenkins]# cat service.yml
apiVersion: v1
kind: Service
metadata:
name: jenkins
spec:
selector:
name: jenkins
type: NodePort
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
nodePort: 30006
- name: agent
port: 50000
protocol: TCP

deployment.yml

[root@k8s-master1 jenkins]# cat deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
labels:
name: jenkins
spec:
replicas: 1
selector:
matchLabels:
name: jenkins
template:
metadata:
name: jenkins
labels:
name: jenkins
spec:
terminationGracePeriodSeconds: 10
serviceAccountName: jenkins
containers:
- name: jenkins
image: jenkins/jenkins:lts
imagePullPolicy: Always
ports:
- containerPort: 8080
- containerPort: 50000
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 0.5
memory: 500Mi
env:
- name: LIMITS_MEMORY
valueFrom:
resourceFieldRef:
resource: limits.memory
divisor: 1Mi
- name: JAVA_OPTS
value: -Xmx$(LIMITS_MEMORY)m -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 -Duser.timezone=Asia/Shanghai
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
livenessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
securityContext:
fsGroup: 1000
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins-home
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-home
spec:
storageClassName: "managed-nfs-storage"
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi

登录地址:直接输入ingress配置的域名:http://jenkins.test.com

修改插件地址:

由于默认插件源在国外服务器,大多数网络无法顺利下载,需修改国内插件源地址:

cd jenkins_home/updates
sed -i 's/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json && \
sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json

Jenkins Pipeline 及参数化构建

Jenkins参数化构建流程图

Jenkins Pipeline是一套插件,支持在Jenkins中实现集成和持续交付管道;

  • Pipeline通过特定语法对简单到复杂的传输管道进行建模;

    1. 声明式:遵循与Groovy相同语法。pipeline { }
    2. 脚本式:支持Groovy大部分功能,也是非常表达和灵活的工具。node { }
  • Jenkins Pipeline的定义被写入一个文本文件,称为Jenkinsfile。

参考:https://jenkins.io/doc/book/pipeline/syntax/

当前环境中我们需要配置pipeline脚本,我们可以先来创建一个Jenkins-pipeline脚本测试一下

安装pipeline插件 : Jenkins 首页 ------ >系统管理 ------ > 插件管理 ------> 可选插件 ------> 过滤输入pipeline, 安装pipeline插件既可以使用。

流水线中输入以下脚本进行测试

pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building'
}
}
stage('Test') {
steps {
echo 'Testing'
}
}
stage('Deploy') {
steps {
echo 'Deploying'
}
}
}
}

测试结果如下:

日志如下:

控制台输出
Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/pipeline-test
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] echo
Building
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] echo
Testing
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] echo
Deploying
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

输出SUCCESS即成功测试

Jenkins在K8S中动态创建代理

前面我们已经完成了pipeline脚本的测试,但是考虑到Jenkins 主机性能有限,如果我们要运行大批量的任务,Jenkins 主机可能会崩溃,这时我们采用Jenkins-slave的方式,给Jenkins主机增加小弟,由Jenkins主机来部署任务,具体任务和编译则留给小弟去做。

传统的Jenkins Master/Slave架构

K8S中Jenkins Master/Slave架构

添加Kubernetes插件

Kubernetes插件:Jenkins在Kubernetes集群中运行动态代理.

插件介绍:https://github.com/jenkinsci/kubernetes-plugin

新增一个kubernetes 云

当前环境中我们需要将Jenkins和kubernetes 进行关联,让Jenkins可以连通kubernetes 并且自动在kubernetes 中 进行命令操作,需要添加kubernetes 云,操作步骤如下:

Jenkins 首页 ------ > 系统管理 ------ > 系统配置 ------ > 云 ------ > 新增一个云 ------ > Kubernetes

配置一下kubernetes 云,当前我们部署的Jenkins是在kubernetes 中直接部署的pod,Jenkins可以直接通过service 读取到kubernetes的地址,所以我们这个地方输入kubernetes的DNS地址(https://kubernetes.default)就可以了,输入完之后不要忘记点击链接测试哦。

Jenkins地址我们也直接输入DNS地址既可以,地址为(http://jenkins.default),这样我们就新增了一个kubernetes云。

自定义构建Jenkins-Slave镜像推送到镜像仓库

配置所需文件:

[root@k8s-master1 jenkins-slave]# tree
.
├── Dockerfile #构建Jenkins-slave所需
├── helm #helm 命令:用于在Jenkins-slave pod 工作时,执行helm 操作安装helm chart库。
├── jenkins-slave #jenkins-slave所需脚本
├── kubectl #kebectl 命令:用于在Jenkins-slave pod 工作中,执行pod 创建命令和查询pod 运行结果等。
├── settings.xml #Jenkins-slave 所需文件
└── slave.jar #Jenkins-slave jar包 0 directories, 6 files

Jenkins-slave 所需 Dockerfile文件

FROM centos:7
LABEL maintainer passzhang
RUN yum install -y java-1.8.0-openjdk maven curl git libtool-ltdl-devel && \
yum clean all && \
rm -rf /var/cache/yum/* && \
mkdir -p /usr/share/jenkins
COPY slave.jar /usr/share/jenkins/slave.jar
COPY jenkins-slave /usr/bin/jenkins-slave
COPY settings.xml /etc/maven/settings.xml
RUN chmod +x /usr/bin/jenkins-slave
COPY helm kubectl /usr/bin/
ENTRYPOINT ["jenkins-slave"]

参考:https://github.com/jenkinsci/docker-jnlp-slave

参考:https://plugins.jenkins.io/kubernetes

推送Jenkins-slave 镜像到harbor仓库

[root@k8s-master1 jenkins-slave]#
docker build -t jenkins-slave:jdk-1.8 . docker tag jenkins-slave:jdk-1.8 192.168.25.228:8088/library/jenkins-slave:jdk-1.8 docker login 192.168.25.228:8088 #登录私有仓库
docker push 192.168.25.228:8088/library/jenkins-slave:jdk-1.8 #推送镜像到私有仓库

配置好之后,需要使用pipeline 流水线测试一下是否可以直接调用Jenkins-slave ,查看Jenkins-slave 是否正常工作。

测试pipeline脚本:

pipeline {
agent {
kubernetes {
label "jenkins-slave"
yaml """
apiVersion: v1
kind: Pod
metadata:
name: jenkins-slave
spec:
containers:
- name: jnlp
image: 192.168.25.228:8088/library/jenkins-slave:jdk-1.8
"""
}
}
stages {
stage('Build') {
steps {
echo 'Building'
}
}
stage('Test') {
steps {
echo 'Testing'
}
}
stage('Deploy') {
steps {
echo 'Deploying'
}
}
}
}

部署截图如下:

Pipeline 集成 Helm 发布微服务项目

部署步骤:

拉取代码 ——> 代码编译 ——> 单元测试 ——> 构建镜像 ——> Helm部署到K8S 测试

创建新的Jenkins任务k8s-deploy-spring-cloud

增加pipeline脚本:

#!/usr/bin/env groovy
// 所需插件: Git Parameter/Git/Pipeline/Config File Provider/kubernetes/Extended Choice Parameter
// 公共
def registry = "192.168.25.228:8088"
// 项目
def project = "ms"
def git_url = "http://192.168.25.227:9999/root/simple-microservice.git"
def gateway_domain_name = "gateway.test.com"
def portal_domain_name = "portal.test.com"
// 认证
def image_pull_secret = "registry-pull-secret"
def harbor_registry_auth = "9d5822e8-b1a1-473d-a372-a59b20f9b721"
def git_auth = "2abc54af-dd98-4fa7-8ac0-8b5711a54c4a"
// ConfigFileProvider ID
def k8s_auth = "f1a38eba-4864-43df-87f7-1e8a523baa35" pipeline {
agent {
kubernetes {
label "jenkins-slave"
yaml """
kind: Pod
metadata:
name: jenkins-slave
spec:
containers:
- name: jnlp
image: "${registry}/library/jenkins-slave:jdk-1.8"
imagePullPolicy: Always
volumeMounts:
- name: docker-cmd
mountPath: /usr/bin/docker
- name: docker-sock
mountPath: /var/run/docker.sock
- name: maven-cache
mountPath: /root/.m2
volumes:
- name: docker-cmd
hostPath:
path: /usr/bin/docker
- name: docker-sock
hostPath:
path: /var/run/docker.sock
- name: maven-cache
hostPath:
path: /tmp/m2
"""
} }
parameters {
gitParameter branch: '', branchFilter: '.*', defaultValue: '', description: '选择发布的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH'
extendedChoice defaultValue: 'none', description: '选择发布的微服务', \
multiSelectDelimiter: ',', name: 'Service', type: 'PT_CHECKBOX', \
value: 'gateway-service:9999,portal-service:8080,product-service:8010,order-service:8020,stock-service:8030'
choice (choices: ['ms', 'demo'], description: '部署模板', name: 'Template')
choice (choices: ['1', '3', '5', '7', '9'], description: '副本数', name: 'ReplicaCount')
choice (choices: ['ms'], description: '命名空间', name: 'Namespace')
}
stages {
stage('拉取代码'){
steps {
checkout([$class: 'GitSCM',
branches: [[name: "${params.Branch}"]],
doGenerateSubmoduleConfigurations: false,
extensions: [], submoduleCfg: [],
userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]
])
}
}
stage('代码编译') {
// 编译指定服务
steps {
sh """
mvn clean package -Dmaven.test.skip=true
"""
}
}
stage('构建镜像') {
steps {
withCredentials([usernamePassword(credentialsId: "${harbor_registry_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
sh """
docker login -u ${username} -p '${password}' ${registry}
for service in \$(echo ${Service} |sed 's/,/ /g'); do
service_name=\${service%:*}
image_name=${registry}/${project}/\${service_name}:${BUILD_NUMBER}
cd \${service_name}
if ls |grep biz &>/dev/null; then
cd \${service_name}-biz
fi
docker build -t \${image_name} .
docker push \${image_name}
cd ${WORKSPACE}
done
"""
configFileProvider([configFile(fileId: "${k8s_auth}", targetLocation: "admin.kubeconfig")]){
sh """
# 添加镜像拉取认证
kubectl create secret docker-registry ${image_pull_secret} --docker-username=${username} --docker-password=${password} --docker-server=${registry} -n ${Namespace} --kubeconfig admin.kubeconfig |true
# 添加私有chart仓库
helm repo add --username ${username} --password ${password} myrepo http://${registry}/chartrepo/${project}
"""
}
}
}
}
stage('Helm部署到K8S') {
steps {
sh """
common_args="-n ${Namespace} --kubeconfig admin.kubeconfig" for service in \$(echo ${Service} |sed 's/,/ /g'); do
service_name=\${service%:*}
service_port=\${service#*:}
image=${registry}/${project}/\${service_name}
tag=${BUILD_NUMBER}
helm_args="\${service_name} --set image.repository=\${image} --set image.tag=\${tag} --set replicaCount=${replicaCount} --set imagePullSecrets[0].name=${image_pull_secret} --set service.targetPort=\${service_port} myrepo/${Template}" # 判断是否为新部署
if helm history \${service_name} \${common_args} &>/dev/null;then
action=upgrade
else
action=install
fi # 针对服务启用ingress
if [ \${service_name} == "gateway-service" ]; then
helm \${action} \${helm_args} \
--set ingress.enabled=true \
--set ingress.host=${gateway_domain_name} \
\${common_args}
elif [ \${service_name} == "portal-service" ]; then
helm \${action} \${helm_args} \
--set ingress.enabled=true \
--set ingress.host=${portal_domain_name} \
\${common_args}
else
helm \${action} \${helm_args} \${common_args}
fi
done
# 查看Pod状态
sleep 10
kubectl get pods \${common_args}
"""
}
}
}
}

执行结果如下:

当前直接点击构建,构建时前面几次可能会失败,多构建一次,打印出所有参数,既可以直接执行成功。

点击发布gateway-service pod 查看日志结果

+ kubectl get pods -n ms --kubeconfig admin.kubeconfig
NAME READY STATUS RESTARTS AGE
eureka-0 1/1 Running 0 3h11m
eureka-1 1/1 Running 0 3h10m
eureka-2 1/1 Running 0 3h9m
ms-gateway-service-66d695c486-9x9mc 0/1 Running 0 10s
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
Finished: SUCCESS # 执行成功之后,会打印出来pod 信息

发布剩下的服务,并查看结果:

+ kubectl get pods -n ms --kubeconfig admin.kubeconfig
NAME READY STATUS RESTARTS AGE
eureka-0 1/1 Running 0 3h14m
eureka-1 1/1 Running 0 3h13m
eureka-2 1/1 Running 0 3h12m
ms-gateway-service-66d695c486-9x9mc 1/1 Running 0 3m1s
ms-order-service-7465c47d79-lbxgd 0/1 Running 0 10s
ms-portal-service-7fd6c57955-jkgkk 0/1 Running 0 11s
ms-product-service-68dbf5b57-jwpv9 0/1 Running 0 10s
ms-stock-service-b8b9895d6-cb72b 0/1 Running 0 10s
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
Finished: SUCCESS

查看eureka结果:

可以看到所有的服务模块都已经注册到eureka中了。

访问一下前端页面:

可以看到有商品查询出来,代表已经连接数据库,同时业务可以正常运行。大功告成了!

总结环境所需插件

  • 使用Jenkins的插件

    • Git & gitParameter
    • Kubernetes
    • Pipeline
    • Kubernetes Continuous Deploy
    • Config File Provider
    • Extended Choice Parameter
  • CI/CD环境特点
    • Slave弹性伸缩
    • 基于镜像隔离构建环境
    • 流水线发布,易维护
  • Jenkins参数化构建可帮助你完成更复杂环境CI/CD

Jenkins-k8s-helm-harbor-githab-mysql-nfs微服务发布平台实战的更多相关文章

  1. Jenkins-k8s-helm-eureka-harbor-githab-mysql-nfs微服务发布平台实战

    基于 K8S 构建 Jenkins 微服务发布平台 实现汇总: 发布流程设计讲解 准备基础环境 K8s环境(部署Ingress Controller,CoreDNS,Calico/Flannel) 部 ...

  2. 宜信开源|微服务任务调度平台SIA-TASK入手实践

    引言 最近宜信开源微服务任务调度平台SIA-TASK,SIA-TASK属于分布式的任务调度平台,使用起来简单方便,非常容易入手,部署搭建好SIA-TASK任务调度平台之后,编写TASK后配置JOB进行 ...

  3. 宜信开源微服务任务调度平台(SIA-TASK)

    背景 无论是互联网应用或者企业级应用,都充斥着大量的批处理任务.常常需要一些任务调度系统帮助开发者解决问题.随着微服务化架构的逐步演进,单体架构逐渐演变为分布式.微服务架构.在此的背景下,很多原先的任 ...

  4. 微服务管理平台nacos虚拟ip负载均衡集群模式搭建

    一.Nacos简介 Nacos是用于微服务管理的平台,其核心功能是服务注册与发现.服务配置管理. Nacos作为服务注册发现组件,可以替换Spring Cloud应用中传统的服务注册于发现组件,如:E ...

  5. php+mysql的微信文章发布平台

    如何在微信上发表丰富图文的文章? 最近在新浪云平台上做了一个php+mysql的微信文章发布平台,丫丫说. 在线编辑文章,扫一扫即可分享到微信,发到朋友圈,非常简单! http://yayashuo. ...

  6. 微服务治理平台的RPC方案实现

    导读:本文主要探讨了rpc框架在微服务化中所处的位置,需要解决的问题.同时介绍了用友云微服务治理平台的rpc解决方案,为什么选择该方案.该方案提供的好处是什么.同时也会介绍用友RPC框架的基本结构以及 ...

  7. 企业级分布式应用服务EDAS _Dubbo商业版_微服务PaaS平台 【EDAS Serverless 运维 创业】

    企业级分布式应用服务EDAS _Dubbo商业版_微服务PaaS平台_分布式框架 - 阿里云https://www.aliyun.com/product/edas?source_type=yqzb_e ...

  8. mPass多租户系统微服务开发平台

    目录 项目总体架构图 基于SpringBoot2.x.SpringCloud并采用前后端分离的企业级微服务,多租户系统架构微服务开发平台 mPaaS(Microservice PaaS)为租户业务开发 ...

  9. 字节跳动内部微服务架构-Docker实战学习笔记分享 真香

    前言 基于 Spring Cloud 的微服务设计和开发,已经越来越多地得到了更多企业的推广和应用,而 Spring Cloud 社区也在不断的迅速发展壮大之中,近几年时间,Spring Cloud ...

随机推荐

  1. 【codeforces 764A】Taymyr is calling you

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  2. Linux 内核 NuBus 总线

    另一个有趣的, 但是几乎被忘记的, 接口总线是 NuBus. 它被发现于老的 Mac 计算机(那 些有 M68K CPU 家族的). 所有的这个总线是内存映射的(象 M68K 的所有东西), 并且设备 ...

  3. Zookeeper面试总结,年后涨薪轻而易举

    此文不是入门教程,是需要一定的zookeeper基础的 zookeeper应用 同意命名服务 在分布式系统中,各个系统都有可能做为服务提供者,可以向外提供服务,这个时候就需要对服务的名字进行统一规划, ...

  4. Joomla 3.9.13 二次注入分析(CVE-2019-19846)

    目录 前言 分析 更好的注入 利用 总结 补丁分析 前言 这一个需要管理员权限的二次SQL注入,利用起来比较鸡肋.这里仅分享一下挖洞时的思路,不包含具体的poc. 分析 漏洞触发点在component ...

  5. 洛谷$P3756\ [CQOI2017]$老$C$的方块 网络流

    正解:网络流 解题报告: 传送门$QwQ$ 看到不能出现给定的讨厌的图形,简单来说就,特殊边两侧的方格不能同时再连方格. 所以如果出现,就相当于是四种方案?就分别炸四个格子. 然后冷静分析一波之后发现 ...

  6. [系列] Go 如何解析 JSON 数据?

    概述 最近掉进需求坑了,刚爬上来,评估排期出现了严重问题,下面三张图很符合当时的心境. 谈需求 估排期 开始干 为啥会这样,我简单总结了下: 与第三方对接. 跨团队对接. 首次用 Go 做项目. 业务 ...

  7. [NoSQL] 从模型关系看 Mongodb 的选择理由

    往期:Mongodb攻略 回顾 Mongodb 与关系型数据库的对应关系: MySQL   MongoDB database(数据库) database(数据库) table(表) collectio ...

  8. 浅谈Java三大特性之封装

    目录 前言 好处 介绍(实现方式) 示例 小结 感谢阅读!!! 三大特性之浅谈封装 前言 英语:Encapsulation--封装,包装. 面向对象的封装与真实世界的目的是一样的.封装能够使外部访问者 ...

  9. 31.用python中的serial向串口发送和接收数据(案例一)

    代码功能说明:1.向串口助手发送十六进制数据:0X01,0X03,0X00,0X00,0X00,0X01,0X84,0X0A: 2.用串口助手向代码发送数据,并将发送过来的数据保存在数据库中,按数据和 ...

  10. SpringBoot-2.1.1系列二:使用websocket

    1.什么是websocket? WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信--允许服务器主动发送信息给客户端. 2.为什么需要使用 ...