基于 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-eureka-harbor-githab-mysql-nfs微服务发布平台实战的更多相关文章

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

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

  2. Jenkins+GitLab+Docker+SpringCloud实现可持续自动化微服务

    本文很长很长,但是句句干货,点赞关注收藏后有惊喜在文末等你 现有混合云平台的场景下,即有线下和线上的环境,又有测试与正式的场景,而且结合了Docker,导致打包内容有所区分,且服务的发布流程复杂起来, ...

  3. 微服务之SpringCloud实战(四):SpringCloud Eureka源码分析

    Eureka源码解析: 搭建Eureka服务的时候,我们会再SpringBoot启动类加上@EnableEurekaServer的注解,这个注解做了一些什么,我们一起来看. 点进@EnableEure ...

  4. 微服务之SpringCloud实战(二):SpringCloud Eureka服务治理

    服务治理 SpringCloud Eureka是SpringCloud Netflix微服务套件的一部分,它基于Netflix Eureka做了二次封装,主要完成微服务的服务治理功能,SpringCl ...

  5. 微服务之SpringCloud实战(五):SpringCloud Eureka详解

    Eureka详解 在第三节高可用中,实际已经讲解了服务的注册,只不过注册的是Eureka本身,原理相同,通过这几篇文章我相信大家对Eureka有了一定的了解,三个核心角色:服务注册中心.服务提供者和服 ...

  6. 微服务之SpringCloud实战(三):SpringCloud Eureka高可用

    高可用Eureka 高可用我就不再过多解释了,Eureka Server的设计一开始就考虑了高可用的问题,在Eureka的服务治理设计中,所有的节点即是服务提供方也是消费方,注册中心也不例外,上一章中 ...

  7. SpringCloud微服务实战——搭建企业级开发框架(三十四):SpringCloud + Docker + k8s实现微服务集群打包部署-Maven打包配置

      SpringCloud微服务包含多个SpringBoot可运行的应用程序,在单应用程序下,版本发布时的打包部署还相对简单,当有多个应用程序的微服务发布部署时,原先的单应用程序部署方式就会显得复杂且 ...

  8. 十分钟搭建微服务框架(SpringBoot +Dubbo+Docker+Jenkins源码)

    本文将以原理+实战的方式,首先对“微服务”相关的概念进行知识点扫盲,然后开始手把手教你搭建这一整套的微服务系统. 这套微服务框架能干啥? 这套系统搭建完之后,那可就厉害了: 微服务架构 你的整个应用程 ...

  9. 手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)...

    原文:手把手0基础项目实战(一)--教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)... 本文你将学到什么? 本文将以原理+实战的方式,首先对& ...

  10. kubeadm/flannel/dashboard/harbor部署以及服务发布

    kubeadm/flannel/dashboard/harbor部署以及服务发布 目录 kubeadm/flannel/dashboard/harbor部署以及服务发布 一.部署kubeadm 1. ...

随机推荐

  1. TypeScript 面试题汇总(2020 版)

    TypeScript 面试题汇总(2020 版) TypeScript 3.9 https://www.typescriptlang.org/zh/ TypeScript 4.0 RC https:/ ...

  2. @bind decorator

    @bind decorator https://www.npmjs.com/package/bind-decorator https://github.com/NoHomey/bind-decorat ...

  3. vscode & typescript & optional-chaining bug

    vscode & typescript & optional-chaining bug https://www.cnblogs.com/xgqfrms/p/11745541.html ...

  4. Windows定时重新启动(适用于server 2012 r2)

    直接看链接吧:https://jingyan.baidu.com/article/2d5afd69dd8e9d85a2e28eb7.html 开始菜单,找到"计划任务程序"; 2 ...

  5. 🤔 移动端 JS 引擎哪家强?美国硅谷找......

    如果你喜欢我写的文章,可以把我的公众号设为星标 ,这样每次有更新就可以及时推送给你啦 在一般的移动端开发场景中,每次更新应用功能都是通过 Native 语言开发并通过应用市场版本分发来实现的.但是市场 ...

  6. SpringBoot(一):使用IDEA快速搭建一个SpringBoot项目(详细)

    环境: JDK1.8   Maven:3.5.4 1.打开IDEA,右上角选择File→New→Project 选择Spring Initializr(使用IDEA自带的插件创建需要电脑联网) 2.点 ...

  7. Aliyun Oss 上传文件

    目录 Aliyun OSS OSS 简介 OSS 基本概念 OSS 功能概述 OSS 使用 创建存储空间Bucket 创建子目录 Java编码 测试 Aliyun OSS OSS 简介 阿里云对象存储 ...

  8. DNS Rebinding漏洞原理

    目录 SSRF过滤器设计 背景知识 DNS TTL 公网DNS服务器 DNS重绑定 自建DNS服务器 利用步骤图解 实战中的注意事项 防御 参考 DNS Rebinding 广泛用于绕过同源策略.SS ...

  9. Hi3559AV100板载开发系列-pthread_create()下V4L2接口MJPEG像素格式的VIDIOC_DQBUF error问题解决-采用阻塞方式下select监听

     最近一直加班加点进行基于Hi3559AV100平台的BOXER-8410AI板载开发,在开发的过程中,遇到了相当多的问题,其一是板载的开发资料没有且功能不完整,厂家不提供太多售后技术支持,厂家对部分 ...

  10. C语言相关的基础字符串函数

    C语言中没有专门的字符串类型,所以就用字符数组和字符指针形式表示 1 char arr[]="abcdef"; //字符数组表示的字符串 2 char*arr="abce ...