跳到主要内容

准备基础环境

1、代码版本仓库 Gitlab

1.1 部署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 \
lizhenliang/gitlab-ce-zh:latest
gitlab/gitlab-ce:latest

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

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

k8s jenkins yml

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

https://github.com/jenkinsci/kubernetes-plugin

1.2 创建项目,提交测试代码

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

代码分支说明:

  • dev1 交付代码

  • dev2 编写Dockerfile构建镜像

  • dev3 K8S资源编排

  • dev4 增加微服务链路监控

  • master 最终上线

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

git clone -b dev3 https://github.com/lizhenliang/simple-microservice
git clone http://192.168.31.70:9999/root/microservice.git
cp -rf simple-microservice/* microservice
cd microservice
git add .
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
git commit -m 'all'
git push origin master

2、镜像仓库 Harbor

2.1 安装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.31.70
# ./prepare
# ./install.sh --with-chartmuseum
# docker-compose ps

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

2.3 配置Docker可信任

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

# cat /etc/docker/daemon.json 
{"registry-mirrors": ["http://f1361db2.m.daocloud.io"],
"insecure-registries": ["192.168.31.70"]
}
# systemctl restart docker

3、应用包管理器 Helm

3.1 安装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/

3.2 配置国内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

3.3 安装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

3.4 添加repo

# helm repo add  --username admin --password Harbor12345 myrepo http://192.168.31.70/chartrepo/library

3.5 推送与安装Chart

# helm push mysql-1.4.0.tgz --username=admin --password=Harbor12345 http://192.168.31.70/chartrepo/library
# helm install web --version 1.4.0 myrepo/demo

4、微服务数据库 MySQL

# yum install mariadb-server -y
# 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

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

6、持续集成 Jenkins

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

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
//git凭证ID
def git_auth = "b632ed00-fc81-43c8-a746-5aa0673b2658"
//git的url地址
def git_url = "git@192.168.66.100:itheima_group/tensquare_back.git"
//镜像的版本号
def tag = "latest"
//Harbor的url地址
def harbor_url = "192.168.66.102:85"
//镜像库项目名称
def harbor_project = "tensquare"
//Harbor的登录凭证ID
def harbor_auth = "833d1a75-f3db-4aec-9cc4-75a77e423163"

node {
//获取当前选择的项目名称
def selectedProjectNames = "${project_name}".split(",")
//获取当前选择的服务器名称
def selectedServers = "${publish_server}".split(",")

stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
for(int i=0;i<selectedProjectNames.length;i++){
//tensquare_eureka_server@10086
def projectInfo = selectedProjectNames[i];
//当前遍历的项目名称
def currentProjectName = "${projectInfo}".split("@")[0]
//当前遍历的项目端口
def currentProjectPort = "${projectInfo}".split("@")[1]

//定义当前Jenkins的SonarQubeScanner工具
def scannerHome = tool 'sonar-scanner'
//引用当前JenkinsSonarQube环境
withSonarQubeEnv('sonarqube') {
sh """
cd ${currentProjectName}
${scannerHome}/bin/sonar-scanner
"""
}
}


}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,打包微服务工程,上传镜像') {
for(int i=0;i<selectedProjectNames.length;i++){
//tensquare_eureka_server@10086
def projectInfo = selectedProjectNames[i];
//当前遍历的项目名称
def currentProjectName = "${projectInfo}".split("@")[0]
//当前遍历的项目端口
def currentProjectPort = "${projectInfo}".split("@")[1]

sh "mvn -f ${currentProjectName} clean package dockerfile:build"

//定义镜像名称
def imageName = "${currentProjectName}:${tag}"

//对镜像打上标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"

//把镜像推送到Harbor
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {

//登录到Harbor
sh "docker login -u ${username} -p ${password} ${harbor_url}"

//镜像上传
sh "docker push ${harbor_url}/${harbor_project}/${imageName}"

sh "echo 镜像上传成功"
}

//遍历所有服务器,分别部署
for(int j=0;j<selectedServers.length;j++){
//获取当前遍历的服务器名称
def currentServerName = selectedServers[j]

//加上的参数格式:--spring.profiles.active=eureka-server1/eureka-server2
def activeProfile = "--spring.profiles.active="

//根据不同的服务名称来读取不同的Eureka配置信息
if(currentServerName=="master_server"){
activeProfile = activeProfile+"eureka-server1"
}else if(currentServerName=="slave_server"){
activeProfile = activeProfile+"eureka-server2"
}

//部署应用
sshPublisher(publishers: [sshPublisherDesc(configName: "${currentServerName}", transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deployCluster.sh $harbor_url $harbor_project $currentProjectName $tag $currentProjectPort $activeProfile", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])


}

}
}
}


插件 安装Extended Choice Parameter插件 多选框 Git Parameter Publish Over SSH插件
利用Role-based Authorization Strategy 插件来管理Jenkins用户权限 安装Credentials Binding插件 密钥证书 管理 安装 Deploy to container插件 远程部署 Gitlab Hook和GitLab 插件 安装Kubernetes Continuous Deploy插件

stage('编译,构建镜像') {
   //定义镜像名称
   def imageName = "${project_name}:${tag}"
   //编译,安装公共工程
   sh "mvn -f tensquare_common clean install"
   //编译,构建本地镜像
   sh "mvn -f ${project_name} clean package dockerfile:build"
   //给镜像打标签
   sh "docker tag ${imageName}
${harbor_url}/${harbor_project_name}/${imageName}"
//登录Harbor,并上传镜像
   withCredentials([usernamePassword(credentialsId: "${harbor_auth}",
passwordVariable: 'password', usernameVariable: 'username')]) {
      //登录
      sh "docker login -u ${username} -p ${password} ${harbor_url}"
      //上传镜像
      sh "docker push ${harbor_url}/${harbor_project_name}/${imageName}"
   }
   //删除本地镜像
   sh "docker rmi -f ${imageName}"
   sh "docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}"
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server',
transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand:
"/opt/jenkins_shell/deploy.sh $harbor_url $harbor_project_name $project_name
$tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false,
noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '',
remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')],
usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
 }
}

#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
echo "$imageName"
#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag} | awk '{print $1}'`
if [ "$containerId" !=  "" ] ; then
  #停掉容器
 docker stop $containerId
  #删除容器
 docker rm $containerId
echo "成功删除容器"
fi
#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name | awk '{print $3}'`
if [ "$imageId" !=  "" ] ; then
  
  #删除镜像
 docker rmi -f $imageId
echo "成功删除镜像"
fi
# 登录Harbor私服
docker login -u itcast -p Itcast123 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName
echo "容器启动成功"


//把选择的项目信息转为数组
 def selectedProjects = "${project_name}".split(',')

for(int i=0;i<selectedProjects.size();i++){
       //取出每个项目的名称和端口
       def currentProject = selectedProjects[i];
       //项目名称
       def currentProjectName = currentProject.split('@')[0]
       //项目启动端口
       def currentProjectPort = currentProject.split('@')[1]
       sh """
          cd ${currentProjectName}
          ${scannerHome}/bin/sonar-scanner
       """
       echo "${currentProjectName}完成代码审查"
     }



//=====以下为远程调用进行项目部署========
        for(int j=0;j<selectedServers.size();j++){
          //每个服务名称
          def currentServer = selectedServers[j]
          //添加微服务运行时的参数:spring.profiles.active
          def activeProfile = "--spring.profiles.active="
          if(currentServer=="master_server"){
             activeProfile = activeProfile+"eureka-server1"
          }else if(currentServer=="slave_server1"){
             activeProfile = activeProfile+"eureka-server2"
          }
          sshPublisher(publishers: [sshPublisherDesc(configName:
"${currentServer}", transfers: [sshTransfer(cleanRemote: false, excludes: '',
execCommand: "/opt/jenkins_shell/deployCluster.sh $harbor_url
$harbor_project_name $currentProjectName $tag $currentProjectPort
$activeProfile", execTimeout: 120000, flatten: false, makeEmptyDirs: false,
noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '',
remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')],
usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
        }
        echo "${currentProjectName}完成编译,构建镜像"

#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
profile=$6
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
echo "$imageName"
#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag} | awk '{print $1}'`
if [ "$containerId" !=  "" ] ; then
  #停掉容器
docker stop $containerId
  #删除容器
 docker rm $containerId
echo "成功删除容器"
fi
#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name | awk '{print $3}'`
if [ "$imageId" !=  "" ] ; then
  
  #删除镜像
 docker rmi -f $imageId
echo "成功删除镜像"
fi
# 登录Harbor私服
docker login -u itcast -p Itcast123 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName $profile
echo "容器启动成功"


def git_address =
"http://192.168.66.100:82/itheima_group/tensquare_back_cluster.git"
def git_auth = "9d9a2707-eab7-4dc9-b106-e52f329cbc95"
//构建版本的名称
def tag = "latest"
//Harbor私服地址
def harbor_url = "192.168.66.102:85"
//Harbor的项目名称
def harbor_project_name = "tensquare"
//Harbor的凭证
def harbor_auth = "71eff071-ec17-4219-bae1-5d0093e3d060"
podTemplate(label: 'jenkins-slave', cloud: 'kubernetes', containers: [
  containerTemplate(
    name: 'jnlp',
    image: "192.168.66.102:85/library/jenkins-slave-maven:latest"
 ),
  containerTemplate(
    name: 'docker',
    image: "docker:stable",
    ttyEnabled: true,
    command: 'cat'
 ),
],
 volumes: [
  hostPathVolume(mountPath: '/var/run/docker.sock', hostPath:
'/var/run/docker.sock'),
  nfsVolume(mountPath: '/usr/local/apache-maven/repo', serverAddress:
'192.168.66.101' , serverPath: '/opt/nfs/maven'),
],
)
{
 node("jenkins-slave"){
   // 第一步
   stage('拉取代码'){
    checkout([$class: 'GitSCM', branches: [[name: '${branch}']],
userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_address}"]]])
  }
   // 第二步
   stage('代码编译'){
     //编译并安装公共工程
    sh "mvn -f tensquare_common clean install"
  }
   // 第三步
   stage('构建镜像,部署项目'){
    //把选择的项目信息转为数组
def selectedProjects = "${project_name}".split(',')
      for(int i=0;i<selectedProjects.size();i++){
        //取出每个项目的名称和端口
        def currentProject = selectedProjects[i];
        //项目名称
        def currentProjectName = currentProject.split('@')[0]
        //项目启动端口
        def currentProjectPort = currentProject.split('@')[1]
        //定义镜像名称
def imageName = "${currentProjectName}:${tag}"
//编译,构建本地镜像
sh "mvn -f ${currentProjectName} clean package
dockerfile:build"
container('docker') {
//给镜像打标签
sh "docker tag ${imageName}
${harbor_url}/${harbor_project_name}/${imageName}"
//登录Harbor,并上传镜像
withCredentials([usernamePassword(credentialsId:
"${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')])
{
 //登录
 sh "docker login -u ${username} -p ${password}
${harbor_url}"
 //上传镜像
 sh "docker push
${harbor_url}/${harbor_project_name}/${imageName}"
}
//删除本地镜像
sh "docker rmi -f ${imageName}"
sh "docker rmi -f
${harbor_url}/${harbor_project_name}/${imageName}"
}
    }
  }
}
}

![3521d1f51f730aa037f1ae759f584426.png] (3521d1f51f730aa037f1ae759f584426.png)

![03d5624f33602bf9512e711e29759526.png] (03d5624f33602bf9512e711e29759526.png)

![329776482ce0d185d3af248781962ff6.png] (329776482ce0d185d3af248781962ff6.png)

![5a6b79fb93e2ffc4010757119efe67d4.png] (5a6b79fb93e2ffc4010757119efe67d4.png)

![60a88b71e947dd1f0e1a6d8ee0dbf0f5.png] (60a88b71e947dd1f0e1a6d8ee0dbf0f5.png)