systemctl status firewalld.service
systemctl stop firewalld.service
yum -y install policycoreutils openssh-server openssh-ckuebts postfix
systemctl enable sshd && sudo systemctl start sshd
systemctl enable postfix && systemctl start postfix
firewall-cmd --add-service=ssh --permanent
firewall-cmd --add-service=http --permanent
firewall-cmd --reload
rpm -ivh gitlab-ce-12.4.2-ce.0.el7.x86_64.rpm
vi /etc/gitlab/gitlab.rb
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
yum install java-1.8.0-openjdk* -y
rpm -ivh jenkins-2.346.1-1.1.noarch.rpm
vi /etc/sysconfig/jenkins
systemctl start jenkins
把端口添加到防火墙
访问 http://192.168.174.129:8888/ 发现配置的8888没有生效
cat /var/lib/jenkins/secrets/initialAdminPassword 获取密码
跳过插件安装
安装插件
进入Manage Jenkins -> Pulgin Manager
sed -i 's/http:\/\/updates.jenkinsci.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
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
安装完成
选择新下载的策略并保存
进入Manage Roles
item roles中新建项目权限
保存
user manager中 新建两个用户
使用新用户登陆做测试
使用管理员账号分配权限
新建两个项目
yum install git -y
用户密码的方式
选择刚才创建的test-git项目
ssh私钥凭证形式
配置好公钥后先在服务器测试一下拉取代码
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.342.b07-1.el7_9.x86_64
export MAVEN_HOME=/opt/maven
export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
进入jenkins Manage Jenkins -> Global Tool Configuration
进入Configure System
JAVA_HOME
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.342.b07-1.el7_9.x86_64
M2_HOME
/opt/maven
PATH+EXTRA
$M2_HOME/bin
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
测试构建maven
如果遇到HTTP ERROR 403 No valid crumb is included in the request
改变 目录 /opt/repo 的用户组 为 jenkins 即可。
yum install java-1.8.0-openjdk* -y
<role rolename="tomcat"/>
<role rolename="role1"/>
<role rolename="manager-script"/>
<role rolename="manager-gui"/>
<role rolename="manager-status"/>
<role rolename="admin-gui"/>
<role rolename="admin-script"/>
<user username="tomcat" password="tomcat" roles="manager-gui,manager-script,tomcat,admin-gui,admin-script"/>
自由风格构建流程
echo "开始编译和打包"
mvn clean package
echo "编译和打包完成"
war路径写一个通配符 target/*.war 扫描所有target下的war包
tomcat管理界面刷新查看 http://192.168.174.130:8080/manager/html
持续集成
重新构建
流水线脚本选择
hello word
Scripted Pipeline
pipeline {
agent any
stages {
stage('pull code') {
steps {
echo 'pull code'
}
}
stage('build project') {
steps {
echo 'build project'
}
}
stage('publish project') {
steps {
echo 'publish project'
}
}
}
}
node {
def mvnHome
stage('pull code') {
echo 'pull code'
}
stage('Build') {
echo 'pull Build'
}
stage('Results') {
echo 'pull Results'
}
}
每30分钟构建一次:
H/30 * * * *
执行时间为 00:00 00:30 。。。
每2个小时构建一次:
H H/2 * * *
每天的8点,12点,22点,一天构建3次: (多个时间点中间用逗号隔开)
0 8,12,22 * * *
每天中午12点定时构建一次
H 12 * * *
每天下午18点定时构建一次
H 18 * * *
在每个小时的前半个小时内的每10分钟
H(0-29)/10 * * * *
每两小时一次,每个工作日上午9点到下午5点
(也许是上午10:38,下午12:38,下午2:38,下午4:38)
H H(9-16)/2 * * 1-5
定时构建
等待2分钟左右,就可以看到开始第12次构建
轮询SCM构建
定时扫描本地代码仓库的代码是否有变更,如果有就触发构建项目
jenkins会定时扫描本地整个项目的代码,增大系统开销,不建议使用
下载插件 Email Extension Template
进入QQ邮箱客户端
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0"
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
<td>(本邮件是程序自动下发的,请勿回复!)</td>
</tr>
<tr>
<td><h2>
<font color="#0000FF">构建结果 - ${BUILD_STATUS}</font>
</h2></td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>项目名称 : ${PROJECT_NAME}</li>
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
<li>触发原因: ${CAUSE}</li>
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
</ul>
</td>
</tr>
<tr>
<td><b><font color="#0B610B">Changes Since Last
Successful Build:</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
</ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:
%c
",showPaths=true,changesFormat="[%a]
%m
",pathFormat=" %p"}
</td>
</tr>
<tr>
<td><b>Failed Test Results</b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td><pre
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
<br /></td>
</tr>
<tr>
<td><b><font color="#0B610B">构建日志 (最后 100行):</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td><textarea cols="80" rows="30" readonly="readonly"
style="font-family: Courier New">${BUILD_LOG, maxLines=100}</textarea>
</td>
</tr>
</table>
</body>
</html>
模板中的参数为jenkins固定值
在jenkinsfile中配置邮件发送
根据提示可以生成对应脚本
pipeline {
agent any
stages {
stage('pull code') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: 'f9831a99-2028-4c36-b10a-d9a36d687f42', url: 'git@192.168.174.128:first_group/web_demo.git']]])
}
}
stage('build project') {
steps{
sh 'mvn clean package'
}
}
stage('publish project') {
steps{
deploy adapters: [tomcat8(credentialsId: '726b8934-8c30-4b05-941a-2d7cdeff151b', path: '', url: 'http://192.168.174.130:8080')], contextPath: null, war: 'target/*.war'
}
}
}
post {
always {
emailext body: '${FILE,path="email.html"}',
subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -${BUILD_STATUS}!',
to: '[email protected]'
}
}
}
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
grant all privileges on *.* to 'root'@'192.168.174.129' identified by '123456' with grant option;
update user set host='%' where user='root';
或者 update user set host='%' where user='localhost'; //看查出来的名字什么
sonar.jdbc.username=root
sonar.jdbc.password=123456
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?
useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=
maxPerformance&useSSL=false
su sonar /opt/sonar/bin/linux-x86-64/sonar.sh start 启动
su sonar /opt/sonar/bin/linux-x86-64/sonar.sh status 查看状态
su sonar /opt/sonar/bin/linux-x86-64/sonar.sh stop 停止
tail -f /opt/sonar/logs/sonar.log 查看日志
# must be unique in a given SonarQube instance
sonar.projectKey=web_demo_freestyle
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=web_demo_freestyle
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
# must be unique in a given SonarQube instance
sonar.projectKey=web_demo_pipline
# this is the name and version displayed in the SonarQube UI. Was mandatoryprior to SonarQube 6.1.
sonar.projectName=web_demo_pipline
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" onWindows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
stage('code check') {
steps{
script {
scannerHome = tool 'sq-scanner'
}
withSonarQubeEnv('sonarqube-scanner') {
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
安装流程
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
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
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum-config-manager \
--add-repo \
https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo
yum list docker-ce --showduplicates | sort -r
sudo yum install docker-ce-18.06.1.ce
docker -v
启动
sudo systemctl start docker
设置开机启动
sudo systemctl enable docker
vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://3e=x2n.mirror.aliyuncs.com"]
}
sudo systemctl daemon-reload
sudo systemctl restart docker
docker info 查看
docker pull openjdk:8-jdk-alpine
curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
tar -xzf harbor-offline-installer-v1.9.2.tgz
mkdir /opt/harbor
mv harbor/* /opt/harbor
cd /opt/harbor
vi harbor.yml
修改hostname和port
hostname: 192.168.174.131
port: 85
zhangsan Zhangsan123456
把Harbor地址加入到jenkins的Docker信任列表 (用于上传镜像)
{
"registry-mirrors": ["https://3e=x2n.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.174.131:85"]
}
{
"registry-mirrors": ["https://3e=x2n.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.174.131:85"]
}
在jenkins服务器执行 ssh-copy-id pro1服务器IP
Configure System 目录下找到 jenkins ssh key
192.168.174.132为pro1,192.168.174.133为pro2
//git凭证ID
def git_auth = "f9831a99-2028-4c36-b10a-d9a36d687f42"
//git的url地址
def git_url = "[email protected]:root/tensquare_parent.git"
//镜像的版本号
def tag = "latest"
//Harbor的url地址
def harbor_url = "192.168.174.131:85"
//镜像库项目名称
def harbor_project = "tensquare"
//Harbor的登录凭证ID
def harbor_auth = "ff0da5ec-efae-4fd5-bad3-d968e9432055"
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 'sq-scanner'
//引用当前JenkinsSonarQube环境
withSonarQubeEnv('sonarqube-scanner') {
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)])
}
}
}
}
#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10086
ENTRYPOINT ["java","-jar","/app.jar"]
#! /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 zhangsan -p Zhangsan123456 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName $profile
echo "容器启动成功"
{
"registry-mirrors": ["https://3eygzx2n.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.174.131:85"]
}
server {
listen 9090;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
还需要关闭selinux,将SELINUX=disabled
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
systemctl enable nginx 设置开机启动
systemctl start nginx 启动
systemctl stop nginx 停止
systemctl restart nginx 重启
//gitlab的凭证
def git_auth = "f9831a99-2028-4c36-b10a-d9a36d687f42"
node {
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']],doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [],userRemoteConfigs: [[credentialsId: "${git_auth}", url:'git@192.168.174.128:root/tensquareadmin.git']]])
}
stage('打包,部署网站') {
//使用NodeJS的npm进行打包
nodejs('nodejs12'){
sh '''
npm install
npm run build
'''
} /
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server',transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '',execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes:false, patternSeparator: '[, ]+', remoteDirectory: '/usr/share/nginx/html',remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/**')],usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
upstream zuulServer{
server 192.168.174.132:10002 weight=1;
server 192.168.174.133:10002 weight=1;
}
server {
listen 85;
listen [::]:85;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
location / {
proxy_pass http://zuulServer/;
}
}
systemctl restart nginx
把端口添加到防火墙
访问 http://192.168.174.132:9090/#/login
192.168.174.128(gitlab)
192.168.174.129(k8s-master)
192.168.174.131(harbor)
192.168.174.132(k8s-node1)
192.168.174.133(k8s-node2)
node('slave1') {
stage('check out') {
checkout([$class: 'GitSCM', branches: [[name: '*/master']],doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [],userRemoteConfigs: [[credentialsId: ' 7ac724bf-f529-4ef8-879a-999748e10efd', url:'[email protected]:root/tensquare_parent.git']]])
}
}
Kubernates+Docker+Jenkins持续集成方案好处
Kubernetes的架构
hostnamectl set-hostname k8s-master
hostnamectl set-hostname k8s-node1
hostnamectl set-hostname k8s-node2
cat >>/etc/hosts<
systemctl status firewalld (确保三台机器防火墙关闭)
vi /etc/sysconfig/selinux
执行 setenforce 0,否则重启才能生效
设置允许路由转发,不对bridge的数据进行处理 (三台都做)
cat > /etc/sysconfig/modules/ipvs.modules <
swapoff -a 临时关闭
vi /etc/fstab 永久关闭
注释掉以下字段
/dev/mapper/cl-swap swap swap defaults 0 0
cat < /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
kubeadm init --kubernetes-version=1.17.0 \
--apiserver-advertise-address=192.168.174.129 \
--image-repository registry.aliyuncs.com/google_containers \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16
报错 [ERROR NumCPU]: the number of available CPUs 1 is less than the required 2
报错detected “cgroupfs” as the Docker cgroup driver. The recommended driver is “systemd”. Please follow the guide at https://kubernetes.io/docs/setup/cri/
如果没运行成功,报错 swap,可以尝试以下命令
节点安装命令保存下来
kubeadm join 192.168.174.129:6443 --token rqydp7.yd7zw5xylk67y9jv \
--discovery-token-ca-cert-hash sha256:df255c8d19eb9eea59201de81d65752d830608079849c04c8c2c2bf7efc8b2e0
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
mkdir k8s
cd k8s
wget https://docs.projectcalico.org/v3.10/manifests/calico.yaml --no-check-certificate
sed -i 's/192.168.0.0/10.244.0.0/g' calico.yaml
kubectl apply -f calico.yaml
kubectl get nodes 查看所有主从节点的状态
kubectl get ns 获取所有namespace资源
kubectl get pods -n {$nameSpace} 获取指定namespace的pod
kubectl describe pod的名称 -n {$nameSpace} 查看某个pod的执行过程
kubectl logs --tail=1000 pod的名称 | less 查看日志
kubectl create -f xxx.yml 通过配置文件创建一个集群资源对象
kubectl delete -f xxx.yml 通过配置文件删除一个集群资源对象
kubectl delete pod名称 -n {$nameSpace} 通过pod删除集群资源
kubectl get service -n {$nameSpace} 查看pod的service情况
yum install -y nfs-utils (三台都要做)
mkdir -p /opt/nfs/jenkins
vi /etc/exports 编写NFS的共享配置
systemctl enable nfs 设置开机启动
systemctl start nfs 启动
在子节点查看
cd nfs-client
创建kube-ops的namespace,因为我们把Jenkins-Master的pod放到kube-ops下
cd jenkins-master
查看分配的端口 kubectl get service -n kube-ops
输入秘钥,不安装插件,创建lisi + 123456
http://192.168.174.132:31162/restart
安装插件
系统管理->系统配置->云->新建云->Kubernetes
构建镜像
镜像拷贝到harbor仓库
def git_address = "http://192.168.174.128:82/root/tensquare_parent.git"
def git_auth = "0e53c6eb-dffc-423c-b430-8d4e48953aa6"
//创建一个Pod的模板,label为jenkins-slave
podTemplate(label: 'jenkins-slave', cloud: 'kubernetes', containers: [
containerTemplate(
name: 'jnlp',
image: "192.168.174.131:85/library/jenkins/jnlp-slave:latest"
)
]
)
{
//引用jenkins-slave的pod模块来构建Jenkins-Slave的pod
node("jenkins-slave"){
// 第一步
stage('拉取代码'){
checkout([$class: 'GitSCM', branches: [[name: 'master']],userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_address}"]]])
}
}
}
def git_address = "http://192.168.174.128:82/root/tensquare_parent.git"
def git_auth = "0e53c6eb-dffc-423c-b430-8d4e48953aa6"
//构建版本的名称
def tag = "latest"
//Harbor私服地址
def harbor_url = "192.168.174.131:85"
//Harbor的项目名称
def harbor_project_name = "tensquare"
//Harbor的凭证
def harbor_auth = "11c4a594-30f7-4f4c-af60-f7e715d1aea1"
podTemplate(label: 'jenkins-slave', cloud: 'kubernetes', containers: [
containerTemplate(
name: 'jnlp',
image: "192.168.174.131:85/library/jenkins/jnlp-slave: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.174.129' , 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]
//定义镜像名称注意:在构建过程会发现无法创建仓库目录,是因为NFS共享目录权限不足,需更改权限还有Docker命令执行权限问题需要手动上传父工程依赖到NFS的Maven共享仓库目录中微服务部署到K8S
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}"
}
}
}
}
build 测试
安装持续集成插件Kubernetes Continuous Deploy
配置全局管理凭证k8s-auth
复制内容,添加到Enter directly
在每个微服务编写deploy.yml
---
apiVersion: v1
kind: Service
metadata:
name: eureka
labels:
app: eureka
spec:
type: NodePort
ports:
- port: 10086
name: eureka
targetPort: 10086
selector:
app: eureka
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: eureka
spec:
serviceName: "eureka"
replicas: 2
selector:
matchLabels:
app: eureka
template:
metadata:
labels:
app: eureka
spec:
imagePullSecrets:
- name: $SECRET_NAME
containers:
- name: eureka
image: $IMAGE_NAME
ports:
- containerPort: 10086
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: EUREKA_SERVER
value: "http://eureka-0.eureka:10086/eureka/,http://eureka-1.eureka:10086/eureka/"
- name: EUREKA_INSTANCE_HOSTNAME
value: ${MY_POD_NAME}.eureka
podManagementPolicy: "Parallel"
server:
port: ${PORT:10086}
spring:
application:
name: eureka
eureka:
server:
# 续期时间,即扫描失效服务的间隔时间(缺省为60*1000ms)
eviction-interval-timer-in-ms: 5000
enable-self-preservation: false
use-read-only-response-cache: false
client:
# eureka client间隔多久去拉取服务注册信息 默认30s
registry-fetch-interval-seconds: 5
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://127.0.0.1:${server.port}/eureka/}
instance:
# 心跳间隔时间,即发送一次心跳之后,多久在发起下一次(缺省为30s)
lease-renewal-interval-in-seconds: 5
# 在收到一次心跳之后,等待下一次心跳的空档时间,大于心跳间隔即可,即服务续约到期时间(缺省为90s)
lease-expiration-duration-in-seconds: 10
instance-id: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}:${server.port}@${random.long(1000000,9999999)}
hostname: ${EUREKA_INSTANCE_HOSTNAME:${spring.application.name}}
修改后的代码提交到gitlab
在129服务器先登录 docker login -u admin -p Harbor12345 192.168.174.131:85
生成docker凭证,用于k8s到docker私服拉取镜像
kubectl create secret docker-registry registry-auth-secret --docker-server=192.168.174.131:85 --docker-username=admin --docker-password=Harbor12345 --docker-email=843635953@qq.com
def git_address = "http://192.168.174.128:82/root/tensquare_parent.git"
def git_auth = "0e53c6eb-dffc-423c-b430-8d4e48953aa6"
//构建版本的名称
def tag = "latest"
//Harbor私服地址
def harbor_url = "192.168.174.131:85"
//Harbor的项目名称
def harbor_project_name = "tensquare"
//Harbor的凭证
def harbor_auth = "11c4a594-30f7-4f4c-af60-f7e715d1aea1"
//k8s凭证
def k8s_auth = "d60faedf-0e56-425f-8c22-6253697381fa"
//定义k8s连接harbor的凭证
def secret_name = "registry-auth-secret"
podTemplate(label: 'jenkins-slave', cloud: 'kubernetes', containers: [
containerTemplate(
name: 'jnlp',
image: "192.168.174.131:85/library/jenkins/jnlp-slave: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.174.129' , 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]
//定义镜像名称注意:在构建过程会发现无法创建仓库目录,是因为NFS共享目录权限不足,需更改权限还有Docker命令执行权限问题需要手动上传父工程依赖到NFS的Maven共享仓库目录中微服务部署到K8S
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}"
}
def deploy_image_name = "${harbor_url}/${harbor_project_name}/${imageName}"
//部署到K8S
sh """
sed -i 's#\$IMAGE_NAME#${deploy_image_name}#'${currentProjectName}/deploy.yml
sed -i 's#\$SECRET_NAME#${secret_name}#'${currentProjectName}/deploy.yml
"""
kubernetesDeploy configs: "${currentProjectName}/deploy.yml",kubeconfigId: "${k8s_auth}"
}
}
}
---
apiVersion: v1
kind: Service
metadata:
name: zuul
labels:
app: zuul
spec:
type: NodePort
ports:
- port: 10020
name: zuul
targetPort: 10020
selector:
app: zuul
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zuul
spec:
serviceName: "zuul"
replicas: 2
selector:
matchLabels:
app: zuul
template:
metadata:
labels:
app: zuul
spec:
imagePullSecrets:
- name: $SECRET_NAME
containers:
- name: zuul
image: $IMAGE_NAME
ports:
- containerPort: 10020
podManagementPolicy: "Parallel"
server:
port: 10020 # 端口
# 基本服务信息
spring:
application:
name: tensquare-zuul # 服务ID
# Eureka配置
eureka:
client:
service-url:
defaultZone: http://eureka-0.eureka:10086/eureka/,http://eureka-1.eureka:10086/eureka/ # Eureka访问地址
instance:
prefer-ip-address: true
# 修改ribbon的超时时间
ribbon:
ConnectTimeout: 1500 # 连接超时时间,默认500ms
ReadTimeout: 3000 # 请求超时时间,默认1000ms
# 修改hystrix的熔断超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMillisecond: 2000 # 熔断超时时长,默认1000ms
# 网关路由配置
zuul:
routes:
admin:
path: /admin/**
serviceId: tensquare-admin-service
gathering:
path: /gathering/**
serviceId: tensquare-gathering
# jwt参数
jwt:
config:
key: tokenstr
ttl: 1800000