K8s
分布式编排管理集群的系统
一、K8s快速入门
1、简介
kubernetes简称k8s。是用于自动部署,扩展和管理容器化应用程序的开源系统。
中文官网:https://kubernetes.io/Zh/
中文社区:https://www.kubernetes.org.cn/
官方文档:https://kubernetes.io/zh/docs/home/
社区文档:https://docs.kubernetes.org.cn/
-
部署方式的进化:
-
传统部署时代:
早期,各个组织机构在物理服务器上运行应用程序。无法为物理服务器中的应用程序定义资源边界,这会导致资源分配问题。 例如,如果在物理服务器上运行多个应用程序,则可能会出现一个应用程序占用大部分资源的情况, 结果可能导致其他应用程序的性能下降。 一种解决方案是在不同的物理服务器上运行每个应用程序,但是由于资源利用不足而无法扩展, 并且维护许多物理服务器的成本很高。
-
虚拟化部署时代:
作为解决方案,引入了虚拟化。虚拟化技术允许你在单个物理服务器的 CPU 上运行多个虚拟机(VM)。 虚拟化允许应用程序在 VM 之间隔离,并提供一定程度的安全,因为一个应用程序的信息 不能被另一应用程序随意访问。
虚拟化技术能够更好地利用物理服务器上的资源,并且因为可轻松地添加或更新应用程序 而可以实现更好的可伸缩性,降低硬件成本等等。
每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统。
-
容器部署时代:
容器类似于 VM,但是它们具有被放宽的隔离属性,可以在应用程序之间共享操作系统(OS)。 因此,容器被认为是轻量级的。容器与 VM 类似,具有自己的文件系统、CPU、内存、进程空间等。 由于它们与基础架构分离,因此可以跨云和 OS
- 好处
- 敏捷应用程序的创建和部署:与使用 VM 镜像相比,提高了容器镜像创建的简便性和效率。
- 持续开发、集成和部署:通过快速简单的回滚(由于镜像不可变性),支持可靠且频繁的 容器镜像构建和部署。
- 关注开发与运维的分离:在构建/发布时而不是在部署时创建应用程序容器镜像, 从而将应用程序与基础架构分离。
可观察性不仅可以显示操作系统级别的信息和指标,还可以显示应用程序的运行状况和其他指标信号。 - 跨开发、测试和生产的环境一致性:在便携式计算机上与在云中相同地运行。
- 跨云和操作系统发行版本的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、 Google Kubernetes Engine 和其他任何地方运行。
- 以应用程序为中心的管理:提高抽象级别,从在虚拟硬件上运行 OS 到使用逻辑资源在 OS 上运行应用程序。
- 松散耦合、分布式、弹性、解放的微服务:应用程序被分解成较小的独立部分, 并且可以动态部署和管理 - 而不是在一台大型单机上整体运行。
- 资源隔离:可预测的应用程序性能。
- 资源利用:高效率和高密度。
- 好处
-
2、架构
- 整体主从方式
Node节点被Master管理,Node节点负责干活,Master负责管理下命令等…
可通过左侧的UI可视化界面或者CLI命令行去发送操作API,API去告诉Master,Master来判断告诉具体是哪个Node节点做什么内容
- master节点架构
- Node节点架构
POD是最小的单位
kube-proxy对外代理一个个的Pod
kunelet来管理每个Pod单位
3、概念
4、快速体验
- 安装minikube
https://github.com/kubernetes/minikube/releases
下载minikuber-windows-amd64.exe 改名为minikube.exe
打开virtualBox,打开cmd
运行
minikube start --vm-driver=virtualbox --registry-mirror=https://registry.docker-cn.com
等待20分钟即可。
- 体验nginx部署升级
提交一个nginx deployment
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
升级 nginx deployment
kubectl apply -f https://k8s.io/examples/application/deployment-update.yaml
扩容
nginx deployment
二、K8s集群安装
1、kubeadm
kubeadm是官方社区推出的一个用于快速部署kuberneters集群的工具
。
这个工具能通过两条指令完成一个kuberneters集群的部署
- 创建一个master节点
$ kuberneters init
- 将一个node节点加入到当前集群中
$ kubeadm join <Master节点的IP和端口>
2、前置要求
一台或多台机器,操作系统Centos7.x-86_x64
硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30GB或更多
集群中所有的机器之间网络互通
可以访问外网,需要拉取镜像
禁止Swap分区
3、部署步骤
- 在所有的节点上安装
Docker
和kubeadm
- 不是Kubernetes Master
- 部署容器网络插件
- 部署Kubernetes Node,将节点加入Kubernetes集群中
- 部署DashBoard web页面,可视化查看Kubernetes资源
4、环境准备
①准备工作
- 可以使用vagrant的Vagrantfile文件快速创建三个虚拟机k8s-node1,k8s-node2和k8s-node3。
Vagrantfile
文件内容如下:
Vagrant.configure("2") do |config|
(1..3).each do |i|
config.vm.define "k8s-node#{i}" do |node|
# 设置虚拟机的Box
node.vm.box = "centos/7"
# 设置虚拟机的主机名
node.vm.hostname="k8s-node#{i}"
# 设置虚拟机的IP
node.vm.network "private_network", ip: "192.168.56.#{99+i}", netmask: "255.255.255.0"
# 设置主机与虚拟机的共享目录
# node.vm.synced_folder "~/Documents/vagrant/share", "/home/vagrant/share"
# VirtaulBox相关配置
node.vm.provider "virtualbox" do |v|
# 设置虚拟机的名称
v.name = "k8s-node#{i}"
# 设置虚拟机的内存大小4G
v.memory = 4096
# 设置虚拟机的CPU个数
v.cpus = 4
end
end
end
end
- 网卡
在VirtualBox的“主机网络管理器”中,有两个网卡,网卡1是“网络地址转换”:是为了方便本机和虚拟机同样都能访问到外界互联网。
网卡2是仅主机网络,是内部的私有网络,在配置时我们仅保留一个主机网卡:
- 常规
需要装3个节点,需要消耗很大内存以此磁盘空间
,选择它存储虚拟机的所有文件:
②创建三个虚拟机
- 执行Vagrantfile文件,创建三个虚拟机k8s-node1、k8s-node1和k8s-node3
- 按照博客链接开启远程ssh密码访问
https://blog.csdn.net/weixin_43334389/article/details/115697067
③NAT网络和前置环境
- 添加NAT网络
在网络地址转换(NAT)的模式下,三个节点的eth0,IP地址相同。而这些地址是供kubernetes集群通信用的,不能相同。
为每个虚拟机添加NAT网络:
在“高级”选项中,刷新一下生成新的MAC地址,此时三者的eth0的IP地址为:
ip addr#查看eth0对应的ip地址
10.0.2.15
10.0.2.4
10.0.2.55
④设置Linux环境
- 关闭防火墙
在开发模式下,将其关闭,不用配置各种进出规则了。
systemctl stop firewalld
systemctl disable firewalld
- 关闭selinux安全规则检查
# 全局禁掉
sed -i 's/enforcing/disabled/' /etc/selinux/config
# 关闭当前会话窗口
setenforce 0
- 关闭swap内存交换分区
该分区会影响kubernetes的性能。
#临时关闭,当前会话
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab #永久关闭
free -g #验证,swap必须为0
- 添加主机名和ip映射关系
vi /etc/hosts
10.0.2.15 k8s-node1
10.0.2.4 k8s-node2
10.0.2.5 k8s-node3
三个虚拟机能够互相ping通,且能够ping通外网baidu.com
.。
- 桥接的IPV4流量传递到iptables的链
不执行的话,会有一些流量统计指标的消失。
cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
应用规则:
sysctl --system
- 同步最新时间
yum -y install ntpdate
ntpdate time.windows.com #同步最新时间
- 对系统进行备份
5、所有节点安装docker、kubeadm、kubelet、kubectl
Kubenetes默认CRI(容器运行时)为Docker,因此先安装Docker。
①安装Docker
- 卸载之前的docker
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
- 安装Docker -CE
# 前置依赖
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
# 设置docker repo 的yum 位置
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 安装docker,以及docker-cli
$ sudo yum -y install docker-ce docker-ce-cli containerd.io
- 配置docker加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://eeqh66oo.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
- 启动docker&设置docker开机自启
kubernetes运行时全靠docker的运行时环境,需要开机自启。
systemctl enable docker
基础环境准备好后,可以给三个虚拟机备份一下。
②添加阿里云yum源
- 添加yum源
告诉kubernetes这些yum源地址,需要的东西在哪里安装。
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[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,kubelet和kubectl
- 指定版本安装
# 检查yum源中是否有kuber有关的yum源
yum list|grep kube
yum install -y kubelet-1.17.3 kubeadm-1.17.3 kubectl-1.17.3
# 开机启动并启动
systemctl enable kubelet
systemctl start kubelet
- 查看kubelet启动状态
systemctl status kubelet
启动中,由于我们还有一些东西没有配置,启动不起来很正常。
④部署k8s-master
- 使用下面的命令,那个镜像下失败后,需要等待很长时间。
apiserver-advertise-address
是master机的ip地址
service-cidr
是service子网
pod-network-cidr
是pod子网
kubeadm init \
--apiserver-advertise-address=10.0.2.15 \
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
--kubernetes-version v1.17.3 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=10.244.0.0/16
kubeadm init \
--apiserver-advertise-address=172.22.30.3 \
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
--kubernetes-version v1.17.3 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=10.244.0.0/16
因此,暂时不使用上面的初始化命令,首先使用下面的master_images.sh
命令进行执行下载镜像,还可以查看进度,文件内容如下:
#!/bin/bash
images=(
kube-apiserver:v1.17.3
kube-proxy:v1.17.3
kube-controller-manager:v1.17.3
kube-scheduler:v1.17.3
coredns:1.6.5
etcd:3.4.3-0
pause:3.1
)
for imageName in ${images[@]} ; do
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
# docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
done
然后再运行初始化命令:
$ kubeadm init \
--apiserver-advertise-address=10.0.2.15 \
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
--kubernetes-version v1.17.3 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=10.244.0.0/16
–apiserver-advertise-address=10.0.2.15 :这里的IP地址是master主机的地址,为上面的eth0网卡的地址;
运行命令之后,会有下面的提示, (Kubernetes control-plane)Kubernetes控制面板初始化成功:
然后,按照提示创建一个用户:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
可以参考下面网址:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
- 在
node2/3
中执行下面命令,为kubernetes添加节点:
kubeadm join 10.0.2.15:6443 --token mmm5wg.30nuvjon44z9a22h \
--discovery-token-ca-cert-hash sha256:62e44803f6c1e30e86a9d2a1f58f3636aae09850cb5feb5d2c7fd949c5d7d5c4
kubeadm join 172.22.30.3:6443 --token ywh9li.cd9rwd6mhmqyxghr \
--discovery-token-ca-cert-hash sha256:83e0d249a4760c59b13be6b8e08b4701267bf998d1361747be5be42dd59aa60b
我们需要按照下面的(3)首先部署一个网络,有网络之后其他人才能够进来构成网络,然后在两个slave节点(k8s-node2、k8s-node3)执行上述命令:
在k8s-node2节点显示:
在master节点中使用下面命令查看节点加入状况:
#获取所有节点
kubectl get nodes
使用下面命令监控pods运行状态:
watch kubectl get pod -n kube-system -o wide
当flannel文件运行起来后,集群中加入的节点就会ready状态:
- 安装Pod网络插件(CNI)
# 部署一个应用
kubectl apply -f kube-flannel.yml
# 删除这个文件中指定的所有资源
kubectl delete -f kube-flannel.yml
该命令会为整个集群安装非常多的规则和组件。
通过下面指令查看pods:
# 查看指定名称空间的pods
kubectl get pods -n kube-system
# 查看指定所有名称空间的pods
kubectl get pods --all-namespaces
# 监控pod进度
watch kubectl get pod -n kube-system -o wide
6、使用
①基本操作
- 操作
部署一个tomcat
# 创建一个部署
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8
# 可以获取到tomcat信息
kubectl get pods -o wide
容器创建中:
创建四个文件,在第一个文件中,可以看到tomcat创建在node2节点:
查看node2节点相关镜像,可以看到该节点下载和运行了tomcat镜像:
在默认命名空间中:
当我们模拟宕机情况,将node2关掉电源,master节点中需要过一点时间才能检测到容灾恢复
在我的电脑中,master节点中需要5分钟左右才能在node3中重新拉起一个tomcat:
- 暴露tomcat访问
#Pod的80映射容器tomcat的8080;
#service会代理Pod的80
# 封装成的service模式为NodePort,随机分配一个端口进行暴露
# --port pod的端口
# --target-port pod里面的tomcat容器的端口
# --type指定以何种方式暴露端口
kubectl expose deployment tomcat6 --port=80 --target-port=8080 --type=NodePort
#执行完会自动随机一个端口对外暴露
使用外网访问:
http://192.168.56.100:32671/
- 动态扩容副本数量的测试
kubectl get deployment
# 扩容-扩容了多份,所以无论访问哪个node的指定端口,都可以访问到tomcat6
# --replicas=扩容数
kubectl scale --replicas=3 deployment tomcat6
应用升级:kubectl set image(–help查看帮助)
- 删除
# 获取资源后进行删除
kubectl get all
kubectl delete deployment.apps/tomcat6
kubectl delete service/tomcat6
流程:创建deployment会管理replicas,replicas控制pod数量,有pod故障会自动拉起新的pod。
②yaml&基本使用
- 参考网址
# kubectl文档
https://kubernetes.io/zh/docs/reference/kubectl/overview/
# 资源类型
https://kubernetes.io/zh/docs/reference/kubectl/overview/#%e8%b5%84%e6%ba%90%e7%b1%bb%e5%9e%8b
# 格式化输出
https://kubernetes.io/zh/docs/reference/kubectl/overview/
- yaml模板
创建的部署和service都可以使用下面yaml格式进行操作:
查看某个pod的具体信息:
# --dry-run 测试运行并不真正执行;输出一点yaml
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8 --dry-run -o yaml
输出结果:
[root@k8s-node1 k8s]# kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8 --dry-run -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: tomcat6
name: tomcat6
spec:
replicas: 1
selector:
matchLabels:
app: tomcat6
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: tomcat6
spec:
containers:
- image: tomcat:6.0.53-jre8
name: tomcat
resources: {}
status: {}
暴露tomcat访问产生的yaml文件:
③pod、service理解
- 一次部署deployment就是一个controller
- service和deployment之间的关系
service是统一应用访问入口
service之间能够相互访问
,通过访问service,该请求可以转发给里面的pod节点。
- labels 和 selectors之间关系:
- labels 类似给pod打上标签人然后用selectors去选择
- selectors类似jq的id选择器
④Ingress
- 介绍
service以域名方式暴露,外部访问Ingress,通过service将请求转发给pod端口。
步骤:
1、部署Ingress controller
2、创建Ingress规则
- 配置
执行“k8s/ingress-controller.yaml”
kubectl apply -f ingress-controller.yaml
需要等待Ingress启动完成:
- 配置规则
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web
spec:
rules:
- host: tomcat6.kubenetes.com # 使用的域名
http:
paths:
- backend:
serviceName: tomcat6 # 后台服务跟下面的service名对应
servicePort: 80
serviceName
需要和下面对应:
我们以后只需要访问域名tomcat6.kubenetes.com
,就可以访问到后台的tomcat6
服务了。
# 将上面规则添加进ingress-tomcat6.yaml文件中
touch ingress-tomcat6.yaml
# 启动配置文件
kubectl apply -f ingress-tomcat6.yaml
- 配置域名映射
192.168.56.102 tomcat6.kubenetes.com
- 测试
三、kubesphere
1、前置环境
- 安装默认的DhashBoard
# k8s文件下有
kubectl appy -f kubernetes-dashboard.yaml
添加权限
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
spec:
type: NodePort
ports:
- port: 443
targetPort: 8443
nodePort: 3001
selector:
k8s-app: kubernetes-dashboard
访问地址:
http://NodeIP:30001
创建授权账号
kubectl create serviceaccount dashboar-admin -n kube-sysem
kubectl create clusterrolebinding dashboar-admin --clusterrole=cluter-admin --serviceaccount=kube-system:dashboard-admin
kubectl create clusterrolebinding dashboar-admin --clusterrole=cluter-admin --serviceaccount=kube-system:dashboard-admin
使用输出的token登录dashboard:
- 介绍
在这里安装的时候,大约花费了一天时间,主要原因是外网无法访问导致,有些脚本命令无法执行。
具体参考网址有两个,将两个文件结合起来一起看比较好比较好:
https://blog.csdn.net/hancoder/article/details/107612802
https://www.cnblogs.com/wwjj4811/p/14117876.html
概述
安装参考网址:
# v3.0.0版本
https://kubesphere.com.cn/docs/quick-start/minimal-kubesphere-on-k8s/
# v2.1版本参考网址
https://v2-1.docs.kubesphere.io/docs/zh-CN/installation/prerequisites/
- 安装heml
安装给定的get_helm.sh
curl -L https://git.io/get_helm.sh | bash
但是,上面的命令由于翻墙的原因一般都无法执行,推荐使用下面博客的方式在匹配好版本的情况下,进行离线安装:
https://blog.csdn.net/qq_30019911/article/details/113747673
获取安装包
https://get.helm.sh/helm-v2.16.3-linux-amd64.tar.gz
将解压后的文件linux-amd64/helm、linux-amd64/tiller
文件放到/usr/local/bin/
目录中
验证版本
helm version
# Client和Server版本要一致,Tiller初始化完成后会显示这个
Client: &version.Version{SemVer:"v2.16.3", GitCommit:"xx", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.16.3", GitCommit:"xx", GitTreeState:"clean"}
创建权限(master执行)
创建helm-rbac.yaml
文件,将下面配置添加进里面:授权工作
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
启用配置
kubectl apply -f helm-rbac.yaml
- 安装Tiller(master执行)
初始化
# --tiller-image指定镜像,否则会被墙
# 等待节点上部署的tiller完成即可
helm init --service-account=tiller --tiller-image=sapcc/tiller:v2.16.3 --history-max 300
我使用上面的命令无法执行:
使用下面的命令执行:
helm init --service-account=tiller --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.16.3 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
使用下面指令验证是否安装成功:
注:删除命名空间的方法,参考下面的博客:
https://blog.csdn.net/shykevin/article/details/107242163
具体命令为:
kubectl get ns kubesphere-system -o json > kubesphere-system.json
curl -k -H "Content-Type:application/json" -X PUT --data-binary @kubesphere-system.json http://127.0.0.1:8081/api/v1/namespaces/kubesphere-system/finalize
- 安装 OpenEBS
创建 LocalPV 存储类型:
https://v2-1.docs.kubesphere.io/docs/zh-CN/appendix/install-openebs/
检查master 节点是否有 Taint
kubectl describe node k8s-node1 | grep Taint
去掉 master 节点的 Taint:
kubectl taint nodes k8s-node1 node-role.kubernetes.io/master:NoSchedule-
创建 OpenEBS 的 namespace
OpenEBS 相关资源将创建在这个 namespace 下:
kubectl create ns openebs
安装 OpenEBS
# 方式1-通过 Helm 命令来安装
helm init
helm install --namespace openebs --name openebs stable/openebs --version 1.5.0
# 方式2-通过原生 kubectl 命令安装
kubectl apply -f https://openebs.github.io/charts/openebs-operator-1.5.0.yaml
方式1安装会有下面的报错信息,我没有办法解决:
(hint: running `helm repo update` may help)
我开了clash软件,使用的方式2安装,中间需要等待pod启动,需要一定的时间。
查看创建的 StorageClass
安装 OpenEBS 后将自动创建 4 个 StorageClass,查看创建的 StorageClass,这需要一定的时间。
kubectl get sc
将 openebs-hostpath
设置为 默认的 StorageClass
kubectl patch storageclass openebs-hostpath -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
至此,OpenEBS 的 LocalPV 已作为默认的存储类型创建成功。可以通过命令 kubectl get pod -n openebs
来查看 OpenEBS 相关 Pod 的状态,若 Pod 的状态都是 running,则说明存储安装成功。
- 最小化安装kubesphere
kubectl apply -f kubesphere-minimal.yaml
使用下面指令监查日志打印情况:
kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f
代码执行到这里的时候,会有一些卡顿
下面是pod启动完成后的状况:
查看pod启动状况
kubectl get pods --all-namespaces
aa0ea01c418d7403ba19170aa4d834bc432f805b
c1f507eeb02247f3f1f1bb39201da65ceef0dcf1
-Dsonar.login=c1f507eeb02247f3f1f1bb39201da65ceef0dcf1
这是使用该命令查看到的最后运行的状况:
查看日志和pod指令需要一起配合,才能有效监视运行状况。
启动界面:
在这里保存一个镜像文件。
默认网卡(Host-Only:10.0.2.15)在这里不能和宿主机相互ping通,我们拿宿主机所在ip(192.168.56.100)进行访问。
2、定制化安装
点击自定义资源CRD,点击clusterconfiguration ,编辑文件开启相关配置devops、notification等。
3、建立多租户系统
平台的资源一共有三个层级,包括 集群 (Cluster)、 企业空间 (Workspace)、 项目 (Project) 和 DevOps Project (DevOps 工程),层级关系如下图所示,即一个集群中可以创建多个企业空间,而每个企业空间,可以创建多个项目和 DevOps工程,而集群、企业空间、项目和 DevOps工程中,默认有多个不同的内置角色。
多租户系统架构:
(1)添加atgugui-hr角色
授予它user-manager的角色。
(2)ws-manager创建账户
使用atgugui-hr账户登录进系统,创建用户(ws-manager、ws-admin、project-admin、project-regular)。
ws-manager:管理项目的创建,其他无任何作用。
ws-admin:项目空间的leader,是集群中的普通用户。
project-admin:集群中的普通用户,需要将其邀请到工作空间中才能干活。
project-regular:普通用户。
ws-manager创建的账户:
(3)ws-manager创建企业空间
为每一个团队创建一个企业空间,然后他们在自己的企业空间中创建项目,邀请成员。
(4)ws-admin-企业空间管理员
ws-manager为企业空间邀请成员。
ws-admin邀请两个成员,project-admin、project-regular,前者可以创建项目,后者只是一个普通成员,只能查看项目资源,没有任何创建功能,可以进行DevOps。
(5)ws-admin测试
ws-admin在gulimall空间中创建一个项目:
添加项目维护者:
4、WorkPress应用
参考网址:
https://v2-1.docs.kubesphere.io/docs/zh-CN/quick-start/wordpress-deployment/
- 秘钥
配置密钥
Docker Hub中的环境变量为:
对应于配置文件:
kind: Secret
apiVersion: v1
metadata:
name: mysql-secret
namespace: gulimall
annotations:
kubesphere.io/alias-name: MySQL 密钥
kubesphere.io/creator: project-regular
data:
MYSQL_ROOT_PASSWORD: MTIzNDU2
type: Opaque
创建存储卷
创建好的存储卷默认为未挂载状态:
- 创建容器
添加容器镜像
配置环境变量
wordpress需要添加两个环境变量:
添加存储卷
检查 WordPress 组件信息无误后,点击添加,此时 MySQL 和 WordPress 组件信息都已添加完成。也就是应用wordpress-application
牵涉到两个服务wordpress
和mysql
。
- 外网访问
应用创建好之后,将其外网访问,不能访问后台保护的mysql,将wordpress构成一个service暴露出来端口就好了
为wordpress配置外网访问
通过下面网址就可以访问:
http://192.168.56.100:30659/
5、DevOps
- 介绍
概述
参考博客:
http://www.digtime.cn/articles/445/gu-li-shang-cheng-ji-qun-88-k8s-zhi-devops
- 流水线-创建凭证
访问网址:
https://v2-1.docs.kubesphere.io/docs/zh-CN/quick-start/devops-online/
- 流水线-CICD
四、集群
1、介绍
- 概述
集群的目标
集群基本形式
- Mysql常见集群方式
- Mysql-MMM(mysql主主复制管理器)
- MHA(Mysql高可用方面是一个相对成熟的方案)
- InnoDB Cluster(支持自动Failover,强一致性,读写分离,读库高可用,读请求负载均衡,推荐方案)
2、Mysql
- 主从同步
创建Master实例并启动
docker run -p 3307:3306 --name mysql-master \
-v /mydata/mysql/master/log:/var/log/mysql \
-v /mydata/mysql/master/data:/var/lib/mysql \
-v /mydata/mysql/master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
参数说明:
-p 3307:3306:将容器的3306映射到主机的3307端口
-v 挂载
-e 初始化root用户密码
修改master基本配置
vim /mydata/mysql/master/conf/my.cnf
修改内容:
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection=uft8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
注意:skip-name-resolve 一定要加,不然连接mysql会超级慢。
添加master主从复制部分配置
server_id=1
log-bin=mysql-bin
read-only=0
binlog-do-db=gulimall_ums
binlog-do-db=gulimall_pms
binlog-do-db=gulimall_oms
binlog-do-db=gulimall_sms
binlog-do-db=gulimall_wms
binlog-do-db=gulimall_admin
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=infomation_schema
replicate-ignore-db=performance_schema
重启master
- 创建Slave实例并启动
docker run -p 3317:3306 --name mysql-slaver-01 \
-v /mydata/mysql/slaver/log:/var/log/mysql \
-v /mydata/mysql/slaver/data:/var/lib/mysql \
-v /mydata/mysql/slaver/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
修改slaver基本配置
文件路径:
vim /mydata/mysql/slaver/conf/my.cnf
修改内容:
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection=uft8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
添加master主从复制部分配置
server_id=2
log-bin=mysql-bin
read-only=1
binlog-do-db=gulimall_ums
binlog-do-db=gulimall_pms
binlog-do-db=gulimall_oms
binlog-do-db=gulimall_sms
binlog-do-db=gulimall_wms
binlog-do-db=gulimall_admin
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=infomation_schema
replicate-ignore-db=performance_schema
- 为master授权用户来他的同步数据
进入master容器
docker exec -it mysql-master /bin/bash
进入mysql内部(mysql -uroot -p)
# 授权root可远程访问(主从无关,为了方便我们远程连接mysql)
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option; flush privileges;
添加用来同步的用户
-- 核心 授权一个专门用来复制的; 'backup'@'%':任何主机都可以
-- 运行后,master就有一个授权用户
GRANT REPLICATION SLAVE ON *.* TO 'backup'@'%' IDENTIFIED BY '123456';
- 查看master状态
show master status
架构图:
- 配置slaver同步master数据
进入slaver容器
docker exec -it mysql-slaver-01 /bin/bash
进入mysql内部(mysql -uroot -p)
授权root可以远程访问(主从无关,为了方便我们远程连接mysql)
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option; flush privileges;
设置主库连接
change master to master_host='192.168.80.133',master_user='backup',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=0,master_port=3307;
启动从库同步
start slave;
查看从库状态
show slave status
3、分库分表
- 介绍
4、Redis
- 介绍
让每台redis节点负责对应槽位
- 集群搭建
(1)创建6个redis节点
3主3从
,为了进行同步备份,主进行slot数据分片。
执行下面指令:
for port in $(seq 7001 7006); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat <<EOF>/mydata/redis/node-${port}/conf/redis.conf
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.80.133
cluster-announce-port ${port}
cluster-announce-bus-port 1${port}
appendonly yes
EOF
docker run -p ${port}:${port} -p 1${port}:1${port} --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d redis:5.0.7 redis-server /etc/redis/redis.conf; \
done
删除和停止运行的容器:
docker stop ${docker ps -a |grep redis-700 | awk '{print $1}}'}
docker rm $(docker ps -a |grep redis-700 | awk '{print $1}')
(2)使用redis建立集群
# 进入master节点,每一个主机点有一个副本节点
docker exec -it redis-7001 bash
# 自动创建集群,6台机器,每台机器有1个备份机器,3主3从
redis-cli --cluster create 192.168.80.133:7001 192.168.80.133:7002 192.168.80.133:7003 192.168.80.133:7004 192.168.80.133:7005 192.168.80.133:7006 --cluster-replicas 1
5、Elasticsearch
- 介绍
- 集群搭建
3主3从结构图:
(1)准备工作
# 所有之前先运行下面指令,(防止jvm报错)
sysctl -w vm.max_map_count=262144
#只是测试,所以临时修改,永久修改使用下面
echo vm.max_map_count=262144 >> /etc/sysctl.conf
sysctl -p
(2)准备docker网络,搭建docker死人网络
#查看
docker network ls
#创建,桥接模式,子网subnet
docker network create --driver bridge --subnet=172.18.12.0/16 --gateway=172.18.1.1 mynet
#查看网络信息
docker network inspect mynet
#以后使用--network=mynet --ip 172.18.12.x 指定ip
(3)3-Master节点创建
for port in $(seq 1 3); \
do \
mkdir -p /mydata/elasticsearch/master-${port}/config
mkdir -p /mydata/elasticsearch/master-${port}/data
chmod -R 777 /mydata/elasticsearch/master-${port}
cat << EOF >/mydata/elasticsearch/master-${port}/config/elasticsearch.yml
cluster.name:my-es #集群的名称,同一个集群该值必须设置成相同的
node.name:es-master-${port} #该节点的名字
node.master:true #该节点有机会成为master节点
node.data:false #该节点可以存储数据
network.host:0.0.0.0
http.host:0.0.0.0 #所有http均可访问
http.port:920${port}
transport.tcp.port:930${port}
discovery.zen.ping_timeout:10s #设置集群中自动发现其他节点时ping连接的超时时间
discovery.seed_hosts:['172.18.12.21:9301','172.18.12.22:9302','172.18.12.23:9303'] #设置集群中的Master节点的初始列表,可以通过这些节点来自动发现其他新加入集群的节点,es7的新增配置
cluster.initial_master_nodes:['172.18.12.21'] #新集群初始时的候选主节点,es7的新增配置
EOF
docker run --name elasticsearch-node-${port} \
-p 920${port}:920${port} -p 930${port}:930${port} \
--netword=mynet --ip 172.18.12.2${port} \
-e ES_JAVA_OPTS="-Xms300m -Xmx300m" \
-v /mydata/elasticsearch/master-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/master-${port}/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/master-${port}/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
done
(4)3-Node节点创建
for port in $(seq 4 6); \
do \
mkdir -p /mydata/elasticsearch/master-${port}/config
mkdir -p /mydata/elasticsearch/master-${port}/data
chmod -R 777 /mydata/elasticsearch/master-${port}
cat << EOF >/mydata/elasticsearch/master-${port}/config/elasticsearch.yml
cluster.name:my-es #集群的名称,同一个集群该值必须设置成相同的
node.name:es-node-${port} #该节点的名字
node.master:false #该节点有机会成为master节点
node.data:true #该节点可以存储数据
network.host:0.0.0.0
http.host:0.0.0.0 #所有http均可访问
http.port:920${port}
transport.tcp.port:930${port}
discovery.zen.ping_timeout:10s #设置集群中自动发现其他节点时ping连接的超时时间
discovery.seed_hosts:['172.18.12.21:9301','172.18.12.22:9302','172.18.12.23:9303'] #设置集群中的Master节点的初始列表,可以通过这些节点来自动发现其他新加入集群的节点,es7的新增配置
cluster.initial_master_nodes:['172.18.12.21'] #新集群初始时的候选主节点,es7的新增配置
EOF
docker run --name elasticsearch-node-${port} \
-p 920${port}:920${port} -p 930${port}:930${port} \
--netword=mynet --ip 172.18.12.2${port} \
-e ES_JAVA_OPTS="-Xms300m -Xmx300m" \
-v /mydata/elasticsearch/master-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/master-${port}/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/master-${port}/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
done
6、RabbitMQ
- 介绍
镜像模式需要在搭建普通模式后,才能设置
- 搭建集群
https://www.cnblogs.com/dalianpai/p/13197018.html
(1)创建三个节点
docker run -d --hostname rabbitmq01 --name rabbitmq01 \
-v /mydata/rabbitmq/rabbitmq01:/var/lib/rabbitmq -p \
15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='achang' \
rabbitmq:management
#RABBITMQ_ERLANG_COOKIE 为令牌,三个节点需要相同,令牌。
# 分别创建rabbitmq01、rabbitmq02、rabbitmq03,改变上面名
(2)节点加入集群
# 分别进入三个集群,加入集群
#主节点
docker exec -it rabbitmq01 /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
eixt
# 进入第二个节点
docker exec -it rabbitmq02 /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
# 加入主节点
rabbitmqctl join_cluster --ram rabbit@rabbitmq01
rabbitmqctl start_app
eixt
# 进入第三个节点
docker exec -it rabbitmq03 /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
# 加入主节点
rabbitmqctl join_cluster --ram rabbit@rabbitmq01
rabbitmqctl start_app
eixt
此时,该集群是一个普通集群
,会存在单点故障,我们基于它,配置成镜像集群。
(3)实现镜像集群。
#进入主节点
docker exec -it rabbitmq01 /bin/bash
# ^ <--代表全部节点
rabbitmqctl set_policy -p / ha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
rabbitmqctl list_policies -p /
五、部署
1、有状态部署
- 介绍
参考博客:
https://www.cnblogs.com/dalianpai/p/13205077.html
- 部署MySQL
(1)创建配置文件
之后创建mysql-master-pvc挂载卷:
(2)创建有状态服务
挂载配置文件:
选择容器组默认部署,将docker放到不同服务器上:
挂载pvc:
查看部署的master服务:
进入容器组终端,查看my.cnf挂载状况:
该终端相当于连接到容器内部:
(3)配置主从复制
进入master容器组终端,执行下面命令,添加用来同步的用户:
GRANT REPLICATION SLAVE ON *.* TO 'backup'@'%' IDENTIFIED BY '123456';
进入slaver同步主库数据:
#-- gulimall-mysql-master.gulimall:master域名;3306端口号
change master to master_host='gulimall-mysql-master.gulimall',master_user='backup',master_password='123456',master_log_file='mysql-bin.000003',master_log_pos=0,master_port=3306;
#-- 启动同步
start slave;
(4)测试
在主库创建一个数据库:
create database gulimall_oms default CHARACTER set utf8mb4;
查看从库同步情况。
- 部署redis
(1)创建配置文件和pvc
(2)添加启动命令
(3)添加存储卷
(4)添加配置文件
(5)进入终端测试
- 部署ES
(1)创建配置文件和PVC
有三个配置项:
(2)配置环境变量
引用配置文件的值,当环境变量:
(3)挂载pvc
由于配置文件已经在环境变量中进行配置,所以这里不进行挂载了。
(4)测试
在右下角的锤子工具kubectl中进行ping指令测试:
- 部署RabbitMQ
(1)创建pvc
(2)部署
暴露默认端口即可:
挂载存储卷:
- 部署Nacos
(1)创建pvc
(2)部署
添加单机版环境变量:
挂载PVC:
(3)对外暴露访问端口
可以将其编写成无状态服务,可以使用下面的方式:
删除服务:
但是容器中nacos仍然存在:
创建无状态服务,关联容器中的nacos:
指定工作负载:
指定端口:
外网访问:
测试访问:
2、部署基础环境
- 基础环境
#kibana
docker run --name kibana -e ELASTICSEARCH_HOSTS=http:192.168.56.10:9200 -p 5601:5601 -d kibana:7.4.2
#nacos
docker run -env MODE=standalone --name nacos \
-v /mydata/nacos/conf/home/nacos/conf -d -p 8848:8848 nacos/nacos-server:1.1.4
# sentinel-可以制作一个镜像并其他它,暴露访问
docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard:1.6.3
#zipkin-两种方式
docker run -d -p 9411:9411 openzipkin/zipkin
docker run --env STORAGE_TYPE=elasticsearch --env ES_HOMES=192.168.56.10:9200
(1)部署kibana
注意:上面的环境配置中,最后少个S:
ELASTICSEARCH_HOSTS
并添加上nodeport方式的外网访问(有状态服务不是nodeport方式暴露的话,外界无法访问)。
输入对应的端口进行测试(阿里云需要开启端口的安全组访问规则):
如果配置错误的话,我们需要等上一段时间,大约10分钟后kibana还是不可用。正确的话,一分钟左右。
部署到目前为止,资源使用状况如下:
(2)部署zipkin
只需要暴露9411端口就可以了:
配置环境变量:
测试:
(3)部署sentinel
使用别人做好的镜像:
测试:
(4)总结
部署服务:
资源使用界面:
- 部署应用的流程
流程图:
- 理解targetPort、Port、NodePort
- 高可用部署总结
3、生产环境配置抽取
- 操作
(1)使用域名访问的形式访问nacos
# ip地址比较难记,变成下面的线上地址
spring.cloud.nacos.discovery.server-addr=nacos-service.gulimall:8848
nacos-service.gulimall
nacos默认以nodeport方式暴露(开启随机端口),在sentinel终端中无法ping通。
下面开启的随机端口,是因为我们要看可视化界面,这个是要暴露的:
创建一个服务,关联nacos的应用负载:
将nacos包装成使用域名访问的方式。需要进行下面的配置进行关联:
容器端口8848对应服务端口8848,可以进行域名访问(ip地址改变,域名不变,也可以实现负载均衡)。
下一步,不用配置外网访问,只需要集群内部访问即可。此时,在sentinel服务端可以ping同nacos。
nacos在k8s中默认是一个pod,将该pod映射成两种不同的服务,一种是暴露端口号,别人通过网络端口号可以直接访问的,第二种是暴露域名的,在集群内部,其他的pod或者service都可以访问它。
(2)配置生产环境application-prod.properties
- 配置其他服务内网访问
(1)配置redis
redis是一个有状态服务,在sentinel服务中通过域名(gulimall-redis.gulimall)可以直接访问:
(2)配置sentinel同nacos配置
(3)配置zipkin同nacos配置
此时,使用域名的配置如下:
spring.rabbitmq.host=gulimall-rabbitmq.gulimall
spring.redis.host=gulimall-redis.gulimall
spring.cloud.sentinel.transport.dashboard=gulimall-sentinel.gulimall:8333
spring.cloud.nacos.discovery.server-addr=gulimall-nacos2.gulimall:8848
spring.zipkin.base-url=http://gulimall-zipkin.gulimall:9411/
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://gulimall-mysql-master.gulimall:3306/gulimail_pms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
4、创建微服务Dockerfile
- 操作
使用Deckerfile可以为每一个微服务打包成一个镜像,进而上传到dockerHub仓库中。
gulimall-common是一个基础包,Maven在运行打包、编译等命令前,依赖的东西要么在远程仓库,要么在本地仓库,我们写的代码没有在仓库里面
(1)运行打包指令
依赖会安装到本地仓库中,聚合关系会被解析。
# 安装并跳过测试
clean install -Dmaven test skip-true
(2)打包成镜像
# 将dockerfile同目录下的jar打成镜像
docker buil -f Dockerfile -t docker.io/likunlun/admin:1.0 .
有了这个镜像,我们可以在后台启动这个容器了。加入每一个微服务都有一个Dockerfile的话,使用Jenkinsfile将其推送到远程仓库,流水线就比较容易实现。
(3)Dockerfile文件解析
# 依赖的基础镜像是java8
FROM java:8
# jar包启动之后暴露的是8080端口,该容器可以对外再进行一个暴露。
EXPOSE 8080
# 工作数据挂载的目录
VOLUME /tmp
# 类似cp,将jar包复制到 /app.jar 中
ADD target/*.jar /app.jar
# 修改jar包创建时间(可加可不加)
RUN bash -c 'touch /app.jar'
# 容器启动,默认运行的命令
ENTRYPOINT ["java","-jar","/app.jar","--spring.profiles.active=prod"]
# 下面是限制内存的启动
ENTRYPOINT ["java","-jar","-Xms128m","-Xmx300m","/app.jar","--spring.profiles.active=prod"]
5、创建微服务K8S部署描述文件
- 操作
为每个微服务添加deploy部署文件:
kind: Deployment # 资源类型,定义成pod
apiVersion: apps/v1
metadata:
labels:
app: gulimall-product
name: gulimall-product
namespace: gulimall # 对应项目中名称空间
spec: # 规格
replicas: 1
selector:
matchLabels: #匹配
app: gulimall-product
template:
metadata:
labels:
app: gulimall-product
spec:
containers: # 容器名为微服务名 docker run --name
- name: gulimall-product
image: $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:latest # dockerHub镜像地址,动态,从Jenkins中取值
ports:
- containerPort: 8080 # 每一个容器都是这个
protocol: TCP
resource:
limits:
cpu: 1000m
memory: 500mi
requests:
cpu: 10m
memory: 10mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent # 镜像拉取策略
restartPolicy: Always # 停机重启
terminationGracePeriodSeconds: 30
strategy:
type: RollingUpdate # 滚动更新
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10 # 保留历史版本数量
progressDeadlineSeconds: 600
---
kind: Service # 资源类型-service(暴露信息让外界访问)
apiVersion: v1
metadata:
labels:
app: gulimall-product
name: gulimall-product
namespace: gulimall
spec: # 规格
ports:
- name: http
protocol: TCP
port: 8080 # 服务端口
targetPort: 8080 # 容器端口
nodePort: 30013 # 代理端口(编排的端口号)
selector:
app: gulimall-product
type: NodePort
sessionAffinty: None
6、流水线文件
①gitee拉取代码
- 参数化构建
parameters {
string(name: 'PROJECT_VERSION', defaultValue: 'v0.0Beta', description: '')
string(name: 'PROJECT_NAME', defaultValue: '', description: '')
}
parameters
可以接收传递过来的参数,PROJECT_NAME
可以在外面定义参数的值类型
- 环境变量
environment {
DOCKER_CREDENTIAL_ID = 'dockerhub-id'
GITEE_CREDENTIAL_ID = 'gitee-id'
KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
REGISTRY = 'docker.io'
DOCKERHUB_NAMESPACE = 'docker账号'
GITEE_ACCOUNT = '码云账号'
SONAR_CREDENTIAL_ID = 'sonar-qube'
BRANCH_NAME = 'master'
}
- 拉取代码
stages {
stage('拉取代码') {
steps {
git(credentialsId: 'gitee-id', url: '码云地址', branch: 'master', changelog: true, poll: false)
sh 'echo 正在构建 $PROJECT_NAME 版本号: $PROJECT_VERSION 将会提交给 $REGISTRY 镜像仓库'
container('maven') {
sh 'mvn clean install -Dmaven.test.skip=true -gs `pwd`/mvn-settings.xml'
}
}
}
编辑流水线参数:
②Sonar代码质量分析
- 操作
(1)代码
stage('sonar代码质量分析') {
steps {
container('maven') {
withCredentials([string(credentialsId: "$SONAR_CREDENTIAL_ID", variable: 'SONAR_TOKEN')]) {
withSonarQubeEnv('sonar') {
sh 'echo 当前目录 `pwd`'
sh "mvn sonar:sonar -gs `pwd`/mvn-settings.xml -Dsonar.branch=$BRANCH_NAME -Dsonar.login=$SONAR_TOKEN"
}
}
timeout(time: 1, unit: 'HOURS') {
waitForQualityGate true
}
}
}
}
(2)线上环境使用下面阿里云镜像和JDK1.8配置
<settings>
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
</settings>
(3)gulimall父项目pom文件中添加sonar插件
<properties>
<!-- Sonar -->
<!-- 部署时使用sonar代码质量分析需要的 值填${PWD}/./target/jacoco.exec-->
<sonar.jacoco.reportPaths></sonar.jacoco.reportPaths>
<sonar.groovy.binaries>target/classes</sonar.groovy.binaries>
</properties>
<!--sonar插件-->
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<configuration>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent-for-ut</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>agent-for-it</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.6.0.1398</version>
</plugin>
</plugins>
</build>
③构建和推送镜像
- 操作
(1)代码
stage('构建镜像-推送镜像') {
steps {
container('maven') {
sh 'mvn -Dmaven.test.skip=true -gs `pwd`/mvn-settings.xml clean package'
sh 'cd $PROJECT_NAME && docker build -f Dockerfile -t $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER .'
withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$DOCKER_CREDENTIAL_ID" ,)]) {
sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:latest '
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:latest '
}
}
}
}
先进行打包,然后推动到远程DockerHub仓库。首先构建要给快照镜像,之后推送一个最新镜像。
④构建完成
- 操作
(1)部署到k8s
stage('部署到k8s') {
steps {
input(id: 'deploy-to-dev-$PROJECT_NAME', message: '是否将$PROJECT_NAME 部署到集群中?')
kubernetesDeploy(configs: '$PROJECT_NAME/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
(2)给github生成发布版标签
stage('发布版本'){
when{
expression{
return params.PROJECT_VERSION =~ /v.*/
}
}
steps {
container ('maven') {
input(id: 'release-image-with-tag', message: '发布当前版本镜像吗?')
withCredentials([usernamePassword(credentialsId: "$GITEE_CREDENTIAL_ID", passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
sh 'git config --global user.email "484613733@qq.com" '
sh 'git config --global user.name "wei-xhh" '
sh 'git tag -a $PROJECT_VERSION -m "$PROJECT_VERSION" '
sh 'git push http://$GIT_USERNAME:$GIT_PASSWORD@gitee.com/$GITEE_ACCOUNT/gulimall.git --tags --ipv4'
}
sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:$PROJECT_VERSION '
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:$PROJECT_VERSION '
}
}
}
总文件:
pipeline {
agent {
node {
label 'maven'
}
}
stages {
stage('拉取代码') {
steps {
git(credentialsId: 'gitee-id', url: '码云地址', branch: 'master', changelog: true, poll: false)
sh 'echo 正在构建 $PROJECT_NAME 版本号: $PROJECT_VERSION 将会提交给 $REGISTRY 镜像仓库'
container('maven') {
sh 'mvn clean install -Dmaven.test.skip=true -gs `pwd`/mvn-settings.xml'
}
}
}
stage('sonar代码质量分析') {
steps {
container('maven') {
withCredentials([string(credentialsId: "$SONAR_CREDENTIAL_ID", variable: 'SONAR_TOKEN')]) {
withSonarQubeEnv('sonar') {
sh 'echo 当前目录 `pwd`'
sh "mvn sonar:sonar -gs `pwd`/mvn-settings.xml -Dsonar.branch=$BRANCH_NAME -Dsonar.login=$SONAR_TOKEN"
}
}
timeout(time: 1, unit: 'HOURS') {
waitForQualityGate true
}
}
}
}
stage('构建镜像-推送镜像') {
steps {
container('maven') {
sh 'mvn -Dmaven.test.skip=true -gs `pwd`/mvn-settings.xml clean package'
sh 'cd $PROJECT_NAME && docker build -f Dockerfile -t $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER .'
withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$DOCKER_CREDENTIAL_ID" ,)]) {
sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:latest '
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:latest '
}
}
}
}
stage('部署到k8s') {
steps {
input(id: 'deploy-to-dev-$PROJECT_NAME', message: '是否将$PROJECT_NAME 部署到集群中?')
kubernetesDeploy(configs: '$PROJECT_NAME/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('发布版本'){
when{
expression{
return params.PROJECT_VERSION =~ /v.*/
}
}
steps {
container ('maven') {
input(id: 'release-image-with-tag', message: '发布当前版本镜像吗?')
withCredentials([usernamePassword(credentialsId: "$GITEE_CREDENTIAL_ID", passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
sh 'git config --global user.email "484613733@qq.com" '
sh 'git config --global user.name "wei-xhh" '
sh 'git tag -a $PROJECT_VERSION -m "$PROJECT_VERSION" '
sh 'git push http://$GIT_USERNAME:$GIT_PASSWORD@gitee.com/$GITEE_ACCOUNT/gulimall.git --tags --ipv4'
}
sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:$PROJECT_VERSION '
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:$PROJECT_VERSION '
}
}
}
}
environment {
DOCKER_CREDENTIAL_ID = 'dockerhub-id'
GITEE_CREDENTIAL_ID = 'gitee-id'
KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
REGISTRY = 'docker.io'
DOCKERHUB_NAMESPACE = 'docker账号'
GITEE_ACCOUNT = '码云账号'
SONAR_CREDENTIAL_ID = 'sonar-qube'
BRANCH_NAME = 'master'
}
parameters {
string(name: 'PROJECT_VERSION', defaultValue: 'v0.0Beta', description: '')
string(name: 'PROJECT_NAME', defaultValue: '', description: '')
}
}
⑤、迁移数据库
- 暴露给外网访问
(1)给mysql-master指定工作负载
目前mysql-master作为有状态服务没有开启外网访问,如下所示:
因此,需要将其能够进行外网访问,以便迁移数据库:
下一步进行开启nodeport外网访问即可,此时通过下面的30986可以访问mysql:
- 操作
(1)新建数据库和表
renrenfast的数据库配置为:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://gulimall-mysql-master.gulimall:3306/gulimall_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
这样才能读取数据库gulimall_admin中的内容。
7、部署
①Docker镜像操作
- 操作
(1)结合k8s配置修改nginx上游服务器。进行负载均衡
(2)推送镜像到DockerHub
但是比较慢,下面推送镜像到阿里云仓库。
②、整合阿里云镜像仓库
sudo docker login --username=武汉小伦 registry.cn-beijing.aliyuncs.com
sudo docker pull registry.cn-beijing.aliyuncs.com/xiaoun-atguigumall/gulimall-nginx:[镜像版本号]
sudo docker push registry.cn-beijing.aliyuncs.com/xiaoun-atguigumall/gulimall-nginx:[镜像版本号]
③、Jenkins修改阿里云镜像仓库
之前Jenkinsfile文件中推送给DockerHub仓库,全部变成阿里云仓库
DOCKER_CREDENTIAL_ID = 'dockerhub-id'
REGISTRY = 'docker.io' #镜像前置地址变成阿里云
DOCKERHUB_NAMESPACE = 'docker账号'
8、部署微服务
①部署相关微服务
- 操作
(1)部署gateway、auth-server、cart、coupon等12个微服务:
(2)动态获取配置文件中的值
package com.xiaolun.gulimall.seckill.config;
@Bean(destroyMethod="shutdown")
public RedissonClient redisson(@Value("${spring.redis.host}") String url) throws IOException {
(3)修改阿里云镜像仓库为公有仓库
- 第一前置部署Nginx
(1)上传nginx镜像
使用docker commit
对nginx进行打包时,外部的挂载文件打包不进来:
因此,将下面文件放到同一个目录下,进行打包nginx:
Deckerfile文件内容:
FROM nginx
MAINTAINER leifengyang
ADD html.tar.gz /usr/share/nginx/html
ADD conf.tar.gz /etc/nginx
EXPOSE 80
ENTRYPOINT nginx -g "daemon off;"
压缩包可以快速上传,and
指令可以解压压缩包。
执行下面指令进行构建镜像:
docker build -t mynginx:v1.2 -f Dockerfile .
(2)配置阿里云镜像仓库密钥
阿里云账户禁止有中文名
。
(3)添加上传到阿里云中的镜像
从阿里云镜像仓库中拉取。全部使用默认。无pvc。
②、创建网关与应用路由
需要管理员首先开启创建网关路由。
(1)创建负载均衡方式
(2)创建路由规则
所有的域名gulimall.com
都交给gulimall-nginx
服务进行代理(80服务端口)。
在删除nginx服务进行重新部署的时候,首先要删除关联nginx的应用路由,再删除nginx服务。
(3)配置映射
请求访问gulimall.com
域名,请求可以到Kubernetes的任何一条机器上,需要其他节点上安装Ingress的机器
之后,添加成下面的域名方案:
无论访问那个域名下的,全部转给IngressController(39.96.78.4),IngressController按照域名进行匹配。接下来,就需要在gulimall-com应用路由中编辑更多的路由规则:
当我们执行下面请求访问时,请求会打到商品服务:
gulimall.com
但是,由于项目部署到阿里云服务器上,该域名没有进行备案,在内网部署时可以访问,外网时无法访问。这是内网部署时,配置的相关域名:
192.168.10.11 gulimall.com
192.168.10.11 search.gulimall.com
192.168.10.11 item.gulimall.com
192.168.10.11 auth.gulimall.com
192.168.10.11 cart.gulimall.com
192.168.10.11 order.gulimall.com
192.168.10.11 member.gulimall.com
192.168.10.11 seckill.gulimall.com
我使用续断为自己的电脑绑定了内网穿透地址,
并将外网域名放到了nginx的拦截请求里,但是未能奏效:
测试1:
可以看到静态资源文件已经存在。
③、商品系统上线
(1)nginx重新打包
docker commit
命令只能打包最原生的镜像,外面挂载文件无法打进来。
使用下面的Dockerfile文件指令打包镜像(压缩包比较好上传):
# 从官方镜像拉取nginx
FROM nginx
MAINTAINER leifengyang
# 将html.tar.gz放到/usr/share/nginx/html中
ADD html.tar.gz /usr/share/nginx/html
ADD conf.tar.gz /etc/nginx
EXPOSE 80
ENTRYPOINT nginx -g "daemon off;"
打包指令:
将上面生成的镜像上传到阿里云。
④、测试
(1)部署完gulimall-gateway后进行测试
出现下面界面,表示搭建成功:
9、部署Vue项目
①操作
(1)打包
npm run build
会有一个dist文件夹,里面就是我们打包的文件,点击index.html
,输入验证码进行访问,此时验证码请求发送地址为:
http://demo.open.renren.io/renren-fast-server/captcha.jpg?uuid=03e5e584-ff18-4805-8914-07fb85d5d4a1
(2)更改环境配置
使验证码请求给网关发送。将static/config/index-prod.js路径地址进行更改,然后重新打包上传:
// api接口请求地址
// window.SITE_CONFIG['baseUrl'] = 'http://demo.open.renren.io/renren-fast-server';
window.SITE_CONFIG['baseUrl'] = 'http://39.96.92.23:30007/api';
(3)打包镜像
FROM nginx
MAINTAINER leifengyang
# 将静态资源放到nginx中,可以直接访问
ADD dist.tar.gz /usr/share/nginx/html
EXPOSE 80
ENTRYPOINT nginx -g "daemon off;"
之后将镜像推送给阿里云。
让其能够外网访问。
(3)测试1
通过访问vue前端,验证码能够返回,说明vue的访问请求可以通过网关gateway转给renrenfast服务。
点击相关菜单,可以进入相关界面,说明该项目打通了数据库:
执行下面品牌管理访问请求:
http://39.96.92.23:31004/api/product/brand/list?t=1619493398348&page=1&limit=10&key=
返回结果:
{
"msg":"success",
"code":0,
"page":{
"totalCount":4,
"pageSize":10,
"totalPage":1,
"currPage":1,
"list":[
{
"brandId":9,
"name":"华为",
"logo":"https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-18/de2426bd-a689-41d0-865a-d45d1afa7cde_huawei.png",
"descript":"华为",
"showStatus":1,
"firstLetter":"H",
"sort":1
},
{
"brandId":10,
"name":"小米",
"logo":"https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-18/1f9e6968-cf92-462e-869a-4c2331a4113f_xiaomi.png",
"descript":"小米",
"showStatus":1,
"firstLetter":"M",
"sort":1
},
{
"brandId":11,
"name":"oppo",
"logo":"https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-18/5c8303f2-8b0c-4a5b-89a6-86513133d758_oppo.png",
"descript":"oppo",
"showStatus":1,
"firstLetter":"O",
"sort":1
},
{
"brandId":12,
"name":"Apple",
"logo":"https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-18/819bb0b1-3ed8-4072-8304-78811a289781_apple.png",
"descript":"苹果",
"showStatus":1,
"firstLetter":"A",
"sort":1
}
]
}
}
②测试滚动更新
(1)对镜像内容修改后,重新上传镜像到阿里云
(2)版本更新
进入该服务后,再进入工作负载,进行修改镜像:
(3)查看
10、线上预警与监控
- 邮件通知
(1)QQ中开启访问权限
(2)配置邮件服务器
(3)配置规则
执行下面品牌管理访问请求:
http://39.96.92.23:31004/api/product/brand/list?t=1619493398348&page=1&limit=10&key=
返回结果:
{
"msg":"success",
"code":0,
"page":{
"totalCount":4,
"pageSize":10,
"totalPage":1,
"currPage":1,
"list":[
{
"brandId":9,
"name":"华为",
"logo":"https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-18/de2426bd-a689-41d0-865a-d45d1afa7cde_huawei.png",
"descript":"华为",
"showStatus":1,
"firstLetter":"H",
"sort":1
},
{
"brandId":10,
"name":"小米",
"logo":"https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-18/1f9e6968-cf92-462e-869a-4c2331a4113f_xiaomi.png",
"descript":"小米",
"showStatus":1,
"firstLetter":"M",
"sort":1
},
{
"brandId":11,
"name":"oppo",
"logo":"https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-18/5c8303f2-8b0c-4a5b-89a6-86513133d758_oppo.png",
"descript":"oppo",
"showStatus":1,
"firstLetter":"O",
"sort":1
},
{
"brandId":12,
"name":"Apple",
"logo":"https://gulimall-hello.oss-cn-beijing.aliyuncs.com/2019-11-18/819bb0b1-3ed8-4072-8304-78811a289781_apple.png",
"descript":"苹果",
"showStatus":1,
"firstLetter":"A",
"sort":1
}
]
}
}
就此谷粒商城结束了!!!感谢你能看到这里!!!