谷粒商城篇章13--P340-P360--k8s/KubeSphere【高可用集群篇一】

发布于:2025-07-24 ⋅ 阅读:(37) ⋅ 点赞:(0)

1 k8s

1.1 简介

        Kubernetes 简称 k8s。 是用于自动部署, 扩展和管理容器化应用程序的开源系统。

中文官网: https://kubernetes.io/zh/

中文社区: https://www.kubernetes.org.cn/

官方文档: https://kubernetes.io/zh/docs/home/

社区文档: http://docs.kubernetes.org.cn/

1.1.1 为什么需要Kubernetes,它能做什么?

官方文档:Kubernetes官方文档

Kubernetes为你提供:

(1)服务发现和负载均衡 ;(2)存储编排;(3)自动部署和回滚;(4)自动完成装箱计算;

(5)自我修复;(6)密钥与配置管理;(7)批处理执行;(8)水平扩展;

(9)IPv4/IPv6双栈;(10)为可扩展性设计.

1.1.2 Kubernete不是什么

官方文档:Kubernetes官方文档

1.1.3 部署方式的进化

 官方文档:Kubernetes官方文档

docker的两种集群方式对比:K8s和swarm。参考如下:

容器云技术选择之kubernetes和swarm对比_docker swarm pod-CSDN博客

1.2 架构原理&核心概念

1.2.1 架构

1.2.1.1 整体主从方式

如果想部署一个应用,是由Master去调度所有的Node节点,将应用放到一个合适的docker运行环境中

1.2.1.2 Master 节点架构 

  • kube-apiserver
    • 对外暴漏 k8s 的api接口,是外界进行资源操作的唯一入口;
    • 提供认证、授权、访问控制、API 注册和发现等机制。
  • etcd
    • etcd 是兼具一致性和高可用性的键值数据库,可以作为保存 Kubernets 所有集群数据的后台数据库。
    • Kubernets 集群的 etcd 数据库通常需要有个备份计划。
  • kube-scheduler
    • 主节点上的组件,该组件监视那些新创新的未指定运行节点的 Pod,并选择节点让 Pod 在上面运行;
    • 所有对 k8s 的集群操作,都必须经过主节点进行调度
  • kube-controller-manager
    • 这些主节点上运行控制器的组件;
    • 这些控制器包括:
      • 节点控制器(Node Controller):负责在节点出现故障时进行通知和响应。
      • 副本控制器(Replication Controller):负责为系统中的每个副本控制器对象维护正确数量的 Pod。
      • 端点控制器(Endpoints Controller):填充端点(Endpoints)对象(即加入 Service 与 Pod)。
      • 服务账户和令牌控制器(Service Account & Token Controllers):为新的命名空间创建默认账户和 API 访问令牌。
1.2.1.3 Node 节点架构

  • kubelet
    • 一个在集群中每个节点上运行的代理。它保证容器都运行在 Pod 中。
    • 负责维护容器的生命周期,同时也负责Volume(CSI) 和容器网络接口(CNI) 的管理。
  • kube-proxy
    • 负责为Service提供Cluster内部的服务发现和负载均衡。
  • 容器运行环境(Container Runtime)
    • 容器运行环境是负责运行容器的软件。
    • Kubernetes 支持多个容器运行环境:Docker、containerd、cri-o、rktlet 以及任何实现 Kubernetes CRI(容器运行环境接口)。
  • fluentd
    • 是一个守护进程,它有助于提供集群层面日志 

1.2.2 概念

  • Container:容器,可以是 docker 启动的一个容器。
  • Pod:
    • k8s 使用 Pod 来组织一组容器。
    • 一个Pod中的所有容器共享同一网络。
    • Pod 是 k8s 中的最小部署单元。
  • Volume:
    • 声明在 Pod 容器中可访问的文件目录。
    • 可以被挂载在 Pod 中一个或多个容器指定路径下。
    • 支持多种后端存储抽象(本地存储、分布式存储、云存储...)

  • Controllers:更高层次对象,部署和管理 Pod;
    • ReplicaSet:确保预期的 Pod 副本数量。
    • Deplotment:无状态应用部署。
    • StatefulSet:有状态应用部署。
    • DaemonSet:确保所有 Node 都运行一个指定 Pod。
    • Job:一次性任务。
    • Cronjob:定时任务。

解释:

1)无状态应用:购物车等代码属于无状态应用

2)有状态应用:比如mysql(A)会在本地磁盘存储一些数据,如果A宕机,在别的服务器在拉起一个mysql(B),A在本地磁盘存的数据其实就没了。

3)部署应用,其实是kubernetes执行一次controller,比如是有状态部署还是无状态部署、部署多少个,这是一个controller。

  • Deployment:
    • 定义一组 Pod 的副本数目、版本等。
    • 通过控制器(Controller)维持 Pod 数目(自动回复失败的 Pod)。
    • 通过控制器以指定的策略控制版本(滚动升级,回滚等)。

  • Service:
    • 定义一组 Pod 的访问策略。
    • Pod 的负载均衡,提供一个或者多个 Pod 的稳定访问地址。
    • 支持多种方式(ClusterIP、NodePort、LoadBalance)。

  • Label:标签,用于对象资源的查询,筛选

  • Namespace:命名空间,逻辑隔离(所有命名空间的作用)
    • 一个集群内部的逻辑隔离机制(鉴权、资源)。
    • 每个资源都属于一个 namespace。
    • 同一个 namespace 所有资源名不能重复。
    • 不同 namespace 可以资源名重复。

API: 我们通过 kubernetes 的 API 来操作整个集群。 可以通过 kubectl、 ui、 curl 最终发送 http+json/yaml 方式的请求给 API Server, 然后控制 k8s 集群。 k8s 里的所有的资源对象都可以采用 yaml 或 JSON 格式的文件定义或描述 。

1.3 集群搭建

部署步骤,如下:

1.3.1 环境准备

1.3.1.1 VirtualBox配置

1. 全局设定

点击,管理->全局设定

选择一个足够大的位置存储虚拟机相关文件。

2. 主机网络管理器

点击,管理->主机网络管理器

创建网卡

虚拟机创建好后的样子,有两个网卡,如下:

(1)网卡1:网络地址转换(NAT),为了让虚拟机和我们的本机同样都可以访问互联网;

(2)网卡2:仅主机(Host-Only)网络,虚拟机内部共享的私有网络。

1.3.2 创建三个虚拟机

1. 在D盘创建一个新文件夹gulimall_k8s(文件夹名字可取任意英文)存放Vagrantfile文件,文件内容如下:

Vagrant.configure("2") do |config|
	(1..3).each do |i|
		config.vm.define "k8s-node#{i}" do |node|
			# 使用box,必须先挂载好
			node.vm.box = "centos7"
			
			# 设置虚拟机的主机名
			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"
			
			# 使用基于virtualbox虚拟化配置
			node.vm.provider "virtualbox" do |v|
				  v.customize ["modifyvm", :id, "--name", "k8s-node#{i}", "--memory", "4096","--cpus","4"]
			end
			
		end
    end
end

2. 存放Vagrantfile的文件夹cmd进入命令窗口,输入vagrant up 创建并启动虚拟机,如下:

 3. 进入三个虚拟机,开启 root 的密码访问权限。

# 进入虚拟机
vagrant ssh 主机名称

# 切换到root用户
su

密码为vagrant

# 修改SSH的配置文件,开启root的密码访问权限
vi /etc/ssh/sshd_config

a 进入输入模式
修改 PasswordAuthentication yes
esc退出输入模式
:wq 保存退出

# 重启服务
service sshd restart

(1)进入k8s-node1

sshd_config中的修改点,开启密码访问权限,如下: 

(2)进入k8s-node2

同 k8s-node1,开启密码访问权限

(3)进入k8s-node3

4. 使用工具连接三台虚拟机,分别是

k8s-node1(192.168.56.100)、

k8s-node2(192.168.56.101)、

k8s-node3(192.168.56.102),密码都是vagrant,如下:

注意:老师使用的工具是 Xshell,我这里使用 MobaXterm。

1.3.3 NAT网络和前置环境

1.3.3.1 设置NAT网络

1. 在三个节点中都输入以下命令,结果如下:

# 查看当前系统的路由表,默认网卡是eth0
ip route show
# 显示设备的ip地址
ip addr

发现,三个节点的网卡1的ip都一样。 

在kubernetes中,默认网卡eth0的的ip都一样即每个节点的默认ip都一样是不行的。

2. 添加新的NAT网络,步骤,如下:

(1)在 VirtualBox管理器中选中三个虚拟机并关闭电源。

(2)管理->全局设定中,选择网络,点击添加新NAT网络,添加一个NAT。

(3)选中k8s-node1/k8s-node2/k8s-node3->设置,重新生成网络1的网卡,1网络才是kubernets集群中要用的网络,2网络是为了让宿主机连上虚拟机。

3. 启动三台虚拟机

4. 查看网络1的ip地址和查看节点间是否网络互通,是否能连接外网,如下: 

1.3.3.2 前置环境 
1.3.3.2.1 设置 linux 环境(三个节点都执行
  • 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
  • 关闭 selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config
setenforce 0

  • 关闭 swap 
swapoff -a 临时
sed -ri 's/.*swap.*/#&/' /etc/fstab 永久
free -g 验证, swap 必须为 0

  • 添加主机名与 IP 对应关系

可以先使用 ip addr命令查询网卡1(eth0)对应的ip. 

vi /etc/hosts

# 添加如下对应关系
10.0.2.15 k8s-node1
10.0.2.10 k8s-node2
10.0.2.9 k8s-node3

  • 将桥接的 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

1.3.3.2.2 节点备份

前置环境弄好之后可进行备份,必要时可恢复备份。

1.3.4 所有节点安装 Docker、kubeadm、kubelet、kubectl

(三个节点都安装)

Docker:容器

kubeadm:集群部署,kubeadm init(Master)、kubeadm join(Node节点加到集群)

kubelet:Node节点代理

kubectl:命令行

1.3.4.1 安装 Docker

1. 卸载系统之前的 Docker

yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

2. 安装 Docker-CE

yum install -y yum-utils device-mapper-persistent-data lvm2

报错信息,如下:

解决方案,如下:

修改CentOS仓库配置文件,具体修改内容如下。

vi /etc/yum.repos.d/CentOS-Base.repo

baseurl=http://vault.centos.org/7.9.2009/os/$basearch/

baseurl=http://vault.centos.org/7.9.2009/updates/$basearch/

baseurl=http://vault.centos.org/7.9.2009/extras/$basearch/

baseurl=http://vault.centos.org/7.9.2009/centosplus/$basearch/

重新运行,安装 Docker-CE 的命令:yum install -y yum-utils device-mapper-persistent-data lvm2,结果如下:

添加 Docker 官方源,如下: 

# 设置 docker repo 的 yum 位置
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

 如果添加 Docker 官方源,报如下错误,可临时切换DNS:

临时将 DNS 修改为 Google 或阿里云的公共 DNS,重新添加 Docker 官方源,如下:

echo "nameserver 8.8.8.8" > /etc/resolv.conf  # Google DNS
# 或者使用阿里云 DNS
# echo "nameserver 223.5.5.5" > /etc/resolv.conf

安装 docker 、docker-cli ,(注意版本适配问题)如下 :

#安装 docker, 以及 docker-cli
sudo yum install -y docker-ce docker-ce-cli containerd.io

# 安装指定版本与 Kubernetes1.17.3版本匹配【推荐】
yum install -y docker-ce-19.03.8 docker-ce-cli-19.03.8 containerd.io-19.03.8

3. 配置 docker 加速

阿里云加速地址:阿里云镜像加速器

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://自己的.mirror.aliyuncs.com"]
} 
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

4. 启动 docker 设置 docker 开机自启

systemctl enable docker

1.3.4.2 添加阿里云 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

1.3.4.3 安装 kubeadm、kubelet 和 kubectl
# 安装 kubelet kubeadm kubectl
yum install -y kubelet-1.17.3 kubeadm-1.17.3 kubectl-1.17.3

# 设置 kubelet 开机自启
systemctl enable kubelet

# 启动 kubelet
systemctl start kubelet
# 查看 kubelet 的状态
systemctl status kubelet

注意:目前 kubelet 是启动不起来的,还需其他配置。

1.3.5 部署 k8s-master

1.3.5.1 master 节点初始化

1. 将k8s-node1作为主节点,进行重命名,如下: 

2. 由于默认拉取镜像地址 k8s.gcr.io 国内无法访问, 这里指定阿里云镜像仓库地址。 可以手动按照我们的 images.sh 先拉取镜像【直接初始化master节点可能会报错,所以先拉取镜像】,地址变为 registry.aliyuncs.com/google_containers 也可以,如下:

k8s文件夹下,有master_images.sh文件,将k8s文件夹拖至k8s-node1(master)节点下

# 查看当前目录下所有的文件
ls
# 将 k8s 文件夹拖至当前目录下

ls
# 查看 k8s 文件夹下文件的权限
ll
# 让拥有者有 master_images.sh 的读、写、执行权限
chmod 700 master_images.sh

ll
# 执行 master_images.sh 文件
./master_images.sh

注意:执行用Nodepad++编写的 master_images.sh 文件,可能会报以下错误,如下:

说明:windows下编写的脚本在linux下格式存在问题,可以执行以下命令对 master_images.sh 文件进行转换后执行,如下:

sed -i "s/\r//" master_images.sh

3. master节点初始化:【推荐使用 kubeadm 搭建 kubernetes 集群】

        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
# API服务器所公布的其真正在监听的IP地址。如果未设置,则使用默认网络接口。
--apiserver-advertise-address=10.0.2.15
# 指定拉取控制平面镜像的容器仓库
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers
# 指定 kubernetes 版本
--kubernetes-version v1.17.3
# 定义服务(Service)的IP地址范围,这个范围通常是一个CIDR块,用于确保服务之间的通信不会冲突‌。
--service-cidr=10.96.0.0/16
# 指明 pod 网络可以使用的IP地址段
--pod-network-cidr=10.244.0.0/16

如果出现以下信息,说明初始化成功:

注意:Kubernetes 和 Docker之间的版本是否匹配,如果不匹配,master节点初始化也会报错

初始化报错,重置 Kubernetes 集群,在重新执行初始化命令:

kubeadm reset
1.3.5.2 测试 kubectl(主节点执行) 
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

先保存下来,等网络加入完成,在从节点执行以下命令:

kubeadm join 10.0.2.15:6443 --token m6wxar.b2wbt89yghboq4ww \
    --discovery-token-ca-cert-hash sha256:2109e0efa3288a81d26077c0d7d8d4037926b3820402db5793f89028a49e4749

1.3.6 安装 pod 网络插件(CNI)

kubectl apply -f \
https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

以上地址可能被墙, 大家获取上传我们下载好的 flannel.yml 运行即可, 同时 flannel.yml 中指定的 images 访问不到可以去 docker hub 找一个wget yml 的地址

vi 修改 yml 所有 amd64 的地址都修改了即可。等待大约 3 分钟

kubectl get pods -n kube-system 查看指定名称空间的 pods

kubectl get pods --all-namespaces 查看所有名称空间的 pods

这里使用下载好的 kube-flannel.yml,如下

运行kube-flannel.yml即可,如下:

# 应用文件配置
kubectl apply -f kube-flannel.yml

# 删除文件配置
kubectl delete -f kube-flannel.yml

kube-flannel.yml具体内容如下:【flannel.yml中指定的images访问不到,镜像已经改成了阿里云的】

---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: psp.flannel.unprivileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
    seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
    apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
    apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
spec:
  privileged: false
  volumes:
    - configMap
    - secret
    - emptyDir
    - hostPath
  allowedHostPaths:
    - pathPrefix: "/etc/cni/net.d"
    - pathPrefix: "/etc/kube-flannel"
    - pathPrefix: "/run/flannel"
  readOnlyRootFilesystem: false
  # Users and groups
  runAsUser:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  # Privilege Escalation
  allowPrivilegeEscalation: false
  defaultAllowPrivilegeEscalation: false
  # Capabilities
  allowedCapabilities: ['NET_ADMIN']
  defaultAddCapabilities: []
  requiredDropCapabilities: []
  # Host namespaces
  hostPID: false
  hostIPC: false
  hostNetwork: true
  hostPorts:
  - min: 0
    max: 65535
  # SELinux
  seLinux:
    # SELinux is unused in CaaSP
    rule: 'RunAsAny'
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flannel
rules:
  - apiGroups: ['extensions']
    resources: ['podsecuritypolicies']
    verbs: ['use']
    resourceNames: ['psp.flannel.unprivileged']
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes/status
    verbs:
      - patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: flannel
  namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
  labels:
    tier: node
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-amd64
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: beta.kubernetes.io/os
                    operator: In
                    values:
                      - linux
                  - key: beta.kubernetes.io/arch
                    operator: In
                    values:
                      - amd64
      hostNetwork: true
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:amd64
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:amd64
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
          limits:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
            add: ["NET_ADMIN"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
        - name: run
          hostPath:
            path: /run/flannel
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-arm64
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: beta.kubernetes.io/os
                    operator: In
                    values:
                      - linux
                  - key: beta.kubernetes.io/arch
                    operator: In
                    values:
                      - arm64
      hostNetwork: true
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:arm64
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:arm64
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
          limits:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
             add: ["NET_ADMIN"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
        - name: run
          hostPath:
            path: /run/flannel
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-arm
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: beta.kubernetes.io/os
                    operator: In
                    values:
                      - linux
                  - key: beta.kubernetes.io/arch
                    operator: In
                    values:
                      - arm
      hostNetwork: true
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:arm
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:arm
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
          limits:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
             add: ["NET_ADMIN"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
        - name: run
          hostPath:
            path: /run/flannel
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-ppc64le
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: beta.kubernetes.io/os
                    operator: In
                    values:
                      - linux
                  - key: beta.kubernetes.io/arch
                    operator: In
                    values:
                      - ppc64le
      hostNetwork: true
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:ppc64le
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:ppc64le
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
          limits:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
             add: ["NET_ADMIN"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
        - name: run
          hostPath:
            path: /run/flannel
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds-s390x
  namespace: kube-system
  labels:
    tier: node
    app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: beta.kubernetes.io/os
                    operator: In
                    values:
                      - linux
                  - key: beta.kubernetes.io/arch
                    operator: In
                    values:
                      - s390x
      hostNetwork: true
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:s390x
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: registry.cn-zhangjiakou.aliyuncs.com/test-lab/coreos-flannel:s390x
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
          limits:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
             add: ["NET_ADMIN"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
        - name: run
          hostPath:
            path: /run/flannel
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg

# 查看命名空间
kubectl get ns
# 查看所有名称空间的 pods
kubectl get pods --all-namespaces

  • 问题一:【coredns无法正常启动】

# 获取所有节点
kubectl get nodes

coredns无法正常启动,master节点状态为NotReady,说明网络加入存在问题。

原因排查:

检查kubelet的状态,结果如下:

# 检查 kubelet 的状态
systemctl status kubelet

报错信息:failed to find plugin "flannel" in path [/opt/cni/bin]

说明 Kubernetes 无法在指定的路径 /opt/cni/bin 下找到 Flannel CNI 插件。Flannel 是一种网络插件,用于在 Kubernetes 集群中实现 Pod 之间的网络通信。

解决方案:

需要下载 CNI plugins v0.8.6

github下载地址:https://github.com/containernetworking/plugins/releases/tag/v0.8.6

(在1.0.0版本后CNI Plugins中没有flannel)

解压后将 flannel 文件拷贝至 /opt/cni/bin/目录下 

# 创建文件夹
mkdir /opt/cni-plugins
# 将压缩包 cni-plugins-linux-amd64-v0.8.6.tgz 放到 /opt/cni-plugins 路径下

cd /opt/cni-plugins
# 解压 CNI 插件压缩包
tar -zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni-plugins/
# 拷贝 flannel 到 /opt/cni/bin/路径下
cp flannel /opt/cni/bin/

查看节点状态:

master节点处于Ready状态。同理,k8s-node2、k8s-node3进行同样操作,问题解决。

注意:master 节点为 Ready 状态,才可以加入从节点。

1.3.7 加入 Kubernetes Node(从节点)

在 Node 节点执行。

向集群添加新节点,执行在 kubeadm init 输出的 kubeadm join 命令:

确保 node 节点成功。

默认情况下,kubeadm init 生成的 token 有效期是24小时

1. token 过期怎么办

使用 kubeadm token list 命令可以列出所有当前的 token 及其有效期。

kubeadm token list

# 创建 token,并打印出集群所需的命令
kubeadm token create --print-join-command

# 创建一个永不过期的 token,不指定 --ttl 参数,kubeadm 会生成一个默认有效期为24小时的令牌
kubeadm token create --ttl 0 --print-join-command

2. 加入 Kubernetes Node

在 k8s-node2、k8s-node3 执行 kubeadm init 输出的 kubeadm join 命令:

kubeadm join 10.0.2.15:6443 --token m6wxar.b2wbt89yghboq4ww \
    --discovery-token-ca-cert-hash sha256:2109e0efa3288a81d26077c0d7d8d4037926b3820402db5793f89028a49e4749

3. 检查节点状态

执行 watch kubectl get pod -n kube-system -o wide 监控 pod 进度
等 3-10 分钟,完全都是 running 以后使用 kubectl get nodes 检查状态

1.3.8 入门操作 kubernetes 集群

master节点调度任意一个从节点部署一个pod运行tomcat6

1. 部署一个 tomcat

(1)部署一个 tomcat

# 创建部署一个 tomcat
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8

# 可以获取到 tomcat 信息
kubectl get all -o wide

(2)上图可以看出 tomcat 部署在 k8s-node2节点,进入k8s-node2节点进行验证,如下:

# 查询默认命名空间下的Pod
kubectl get pods

# 查询所有命名空间下的Pod
kubectl get pods --all-namespaces

# 查询默认命名空间下的Pod详细信息
kubectl get pods -o wide

# 查看所有资源
kubectl get all

(3)测试容灾恢复,模拟 k8s-node2节点出问题,如下: 

  • 关闭正在运行的tomcat容器,会自动重新拉起一个tomcat容器

  • 模拟k8s-node2宕机 ,可以看到 master 节点又重新在 node3 创建部署一个tomcat

测试完成后,重新启动 k8s-node2,如下:

2. 暴漏 tomcat 访问 

# Pod 的 80 映射容器的 8080; service 会代理 Pod 的 80
kubectl expose deployment tomcat6 --port=80 --target-port=8080 --type=NodePort

--type=NodePort:指定暴漏方式为NodePort,NodePort是外部访问k8s集群中service的端口,可以访问每个节点的端口,都可以访问各个Pod。

# 查看服务
kubectl get svn

# 查看服务的详细信息
kubectl get svn -o wide

任意节点 IP:31428(端口)访问测试,如下:

3. 动态扩容测试

扩容了多份, 所有无论访问哪个 node 的指定端口, 都可以访问到 tomcat6

# 扩容
kubectl scale --replicas=3 deployment tomcat6

# 缩容
kubectl scale --replicas=1 deployment tomcat6

4. 删除

流程: 创建 deployment 会管理 replicas, replicas 控制 pod 数量, 有 pod 故障会自动拉起新的 pod

# 查看所有资源
kubectl get all

# 删除部署信息
kubectl delete deployment.apps/tomcat6

# 删除服务
kubectl delete service/tomcat6

还有一个默认的service,用来监听 443 安全连接端口。

tomcat 都不能在访问,如下:

1.3.9 安装默认 dashboard

1.4 入门

1.4.1 yaml & 基本使用

1.4.1.1 kubectl

1. kubectl 文档

https://kubernetes.io/zh/docs/reference/kubectl/overview/

2. 资源类型

命令行工具 (kubectl) | 资源类型

3. 格式化输出

命令行工具 (kubectl) | 格式化输出

4. 常用操作

命令行工具 (kubectl) | 常用操作

5. 命令参考

kubectl | 命令参考

1.4.1.2 yaml 语法

1. yml 模板

2. yaml 字段解析

参照官方文档

3. yaml 输出

(1)创建部署

# 查看创建部署的帮助信息
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8 --help

# 输出 yaml 格式的 API 对象
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8 --dry-run -o yaml

--help:查看帮助信息。

--dry-run:模拟命令的执行,但不会真正应用到 Kubernetes 集群上。

-o yaml:这个选项指定输出格式为 YAML。这对于查看将要创建的资源定义非常有帮助。 

# 输出 yaml 信息到指定文件 tomcat6.yaml
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8 --dry-run -o yaml > tomcat6.yaml

# 查看文件
ls

# 打开 tomcat6.yaml 删除无用的信息
vi tomcat6.yaml

# 应用 tomcat6.yaml 文件,创建部署 tomcat6(-f:指以文件的形式)
kubectl apply -f tomcat6.yaml

# 查看 pod 信息
kubectl get pods

 tomcat6.yaml 文件信息,如下:

(2)暴露服务

同理暴露服务也可以输出yaml,如下:

(3)Pod

# 查看所有 pod
kubectl get pods

# 查看指定 pod
kubectl get pod tomcat6-5f7ccf4cb9-4tmrk

# pod 的详细信息输出为 yaml

kubectl get pod tomcat6-5f7ccf4cb9-4tmrk -o yaml

# 输出 yaml 信息到指定文件 mypod.yml
kubectl get pod tomcat6-5f7ccf4cb9-4tmrk -o yaml > mypod.yml

# 修改 yaml 文件
vi mypod.yml

# 应用 yaml 文件,创建 pod
kubectl apply -f mypod.yml

# 查看 pod 信息
kubectl get pods

修改后的 mypod.yml 详细信息如下: 

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: tomcat6-new
  name: tomcat6-new
  namespace: default
spec:
  containers:
  - image: tomcat:6.0.53-jre8
    imagePullPolicy: IfNotPresent
    name: tomcat6-new
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: nginx

1.4.2 Pod、Service等概念

1.4.2.1 Pod 是什么,Controller 是什么

官方文档:Pod | Kubernetes

Pod 和 控制器

        控制器可以为您创建多个 Pod,管理副本和上线,并在集群范围内提供自修复能力。例如, 如果一个节点失败, 控制器可以在不同的节点上调度一样的替身来自动替换 Pod。包含一个或多个 Pod 的控制器一些示例包括:
Deployment
StatefulSet
DaemonSet
控制器通常使用您提供的 Pod 模板来创建它所负责的 Pod。

1.4.2.2 Deployment&Service 是什么

1.4.2.3 Service 的意义

先删除之前的部署和 Pod,再重新部署

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: {}

修改后

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat6
  template:
    metadata:
      labels:
        app: tomcat6
    spec:
      containers:
      - image: tomcat:6.0.53-jre8
        name: tomcat

暴露

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: tomcat6
  name: tomcat6
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: tomcat6
  type: NodePort
status:
  loadBalancer: {}

部署暴露合并

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat6
  template:
    metadata:
      labels:
        app: tomcat6
    spec:
      containers:
      - image: tomcat:6.0.53-jre8
        name: tomcat
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: tomcat6
  type: NodePort

1、 部署一个 nginx

kubectl create deployment nginx --image=nginx

2、 暴露 nginx 访问

kubectl expose deployment nginx --port=80 --type=NodePort

统一应用访问入口;
Service 管理一组 Pod。
防止 Pod 失联(服务发现) 、 定义一组 Pod 的访问策略。


现在 Service 我们使用 NodePort 的方式暴露, 这样访问每个节点的端口, 都可以访问到这
个 Pod, 如果节点宕机, 就会出现问题。

1.4.2.4 labels and selectors

官方文档:标签和选择算符 | Kubernetes

1.4.3 Ingress

1.4.3.1 以 yaml 的形式部署暴露应用

1. 先删除之前的部署和 Pod,再重新部署

先删除部署,其他相关的副本就会被自动删掉 

2. 输出部署 tomcat6 的 yaml,如下:

# 输出部署 tomcat6 的yaml
kubectl create deployment tomcat6 --image=tomcat:6.0.53-jre8 --dry-run -o yaml > tomcat6-deployment.yaml

# 编辑 tomcat6-deployment.yaml
vi tomcat6-deployment.yaml

修改前的 tomcat6-deployment.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: {}

修改后的 tomcat6-deployment.yaml,如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat6
  template:
    metadata:
      labels:
        app: tomcat6
    spec:
      containers:
      - image: tomcat:6.0.53-jre8
        name: tomcat

3. 输出暴露 tomcat6 的yaml,如下: 

# 输出暴露 tomcat6 的yaml
kubectl expose deployment tomcat6 --port=80 --target-port=8080 --type=NodePort --dry-run  -o yaml

yaml 具体内容,如下: 

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: tomcat6
  name: tomcat6
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: tomcat6
  type: NodePort
status:
  loadBalancer: {}

4. 合并 tomcat 部署、 暴露的 yaml,并应用,如下:

# 编辑 tomcat6-deployment.yaml 文件
vi tomcat6-deployment.yaml

# 应用 tomcat6-deployment.yaml 文件
kubectl apply -f tomcat6-deployment.yaml

# 查看所有资源
kubectl get all

编辑后(合并部署和暴露)的 tomcat6-deployment.yaml 文件内容,如下:

【yaml允许多个文档片段,用---分割】

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat6
  template:
    metadata:
      labels:
        app: tomcat6
    spec:
      containers:
      - image: tomcat:6.0.53-jre8
        name: tomcat
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: tomcat6
  name: tomcat6
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: tomcat6
  type: NodePort

5. 测试,浏览器访问任意节点IP:30850

希望以域名的方式访问 tomcat ,并且能够负载均衡,这样的话一个节点宕机还可以通过域名访问到另外正常运行的节点,引入下面的 Ingress

1.4.3.2 Ingress

通过 Service 发现 Pod 进行关联。 基于域名访问。
通过 Ingress Controller 实现 Pod 负载均衡
支持 TCP/UDP 4 层负载均衡和 HTTP 7 层负载均衡

具体步骤,如下: 

1. 部署 Ingress Controller

# 应用 ingress-controller.yaml
kubectl apply -f ingress-controller.yaml

 ingress-controller.yaml 具体内容,如下:

apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: udp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-ingress-serviceaccount
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - "extensions"
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - "extensions"
    resources:
      - ingresses/status
    verbs:
      - update

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: nginx-ingress-role
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - pods
      - secrets
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - configmaps
    resourceNames:
      # Defaults to "<election-id>-<ingress-class>"
      # Here: "<ingress-controller-leader>-<nginx>"
      # This has to be adapted if you change either parameter
      # when launching the nginx-ingress-controller.
      - "ingress-controller-leader-nginx"
    verbs:
      - get
      - update
  - apiGroups:
      - ""
    resources:
      - configmaps
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - endpoints
    verbs:
      - get

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: nginx-ingress-role-nisa-binding
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: nginx-ingress-role
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: nginx-ingress-clusterrole-nisa-binding
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-clusterrole
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---

apiVersion: apps/v1
kind: DaemonSet 
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      hostNetwork: true
      serviceAccountName: nginx-ingress-serviceaccount
      containers:
        - name: nginx-ingress-controller
          image: siriuszg/nginx-ingress-controller:0.20.0
          args:
            - /nginx-ingress-controller
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx
            - --annotations-prefix=nginx.ingress.kubernetes.io
          securityContext:
            allowPrivilegeEscalation: true
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            # www-data -> 33
            runAsUser: 33
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          ports:
            - name: http
              containerPort: 80
            - name: https
              containerPort: 443
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10

---
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  #type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

2. 创建 Ingress 规则,并应用

vi ingress-tomcat6.yml

ingress-tomcat6.yml 具体内容,如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: web
spec:
  rules:
  - host: tomcat6.atguigu.com
    http:
      paths:
        - backend:
           serviceName: tomcat6
           servicePort: 80

注意:规则中的 serviceName对应 tomcat 暴露的name;规则中的servicePort 对应 tomcat 暴露的pod 端口,如下图:

ingress是 Running的状态,在应用 Ingress 规则 ingress-tomcat6.yaml 

3. 以管理员身份打开 SwitchHosts,添加端口映射

4. 测试

在浏览器访问 http://tomcat6.atguigu.com/

2 KubeSphere

默认的 dashboard 没啥用, 我们用 kubesphere 可以打通全部的 devops 链路。Kubesphere 集成了很多套件, 集群要求较高

https://kubesphere.io/

Kuboard 也很不错, 集群要求不高

https://kuboard.cn/support/

2.1 简介

        KubeSphere 是一款面向云原生设计的开源项目, 在目前主流容器调度平台 Kubernetes 之上构建的分布式多租户容器管理平台, 提供简单易用的操作界面以及向导式操作方式, 在降低用户使用容器调度平台学习成本的同时, 极大降低开发、 测试、 运维的日常工作的复杂度。

2.2 安装

2.2.1 前提条件

https://kubesphere.io/docs/v2.1/zh-CN/installation/prerequisites/

注意:上面的地址不可用,可参照下面的地址,如下。

https://kubesphere.io/zh/docs/v3.3/release/release-v210/   【官方文档 3.3版本】

Release Notes - 《KubeSphere v2.1 使用手册》 - 书栈网 · BookStack 【2.1版本】

2.2.2 安装前提环境

2.2.2.1 安装 helm(master 节点执行)

        Helm 是 Kubernetes 的包管理器。 包管理器类似于我们在 Ubuntu 中使用的 apt、 Centos中使用的 yum 或者 Python 中的 pip 一样, 能快速查找、 下载和安装软件包。 Helm 由客户端组件 helm 和服务端组件 Tiller 组成, 能够将一组 K8S 资源打包统一管理, 是查找、共享和使用为 Kubernetes 构建的软件的最佳方式。

1. 安装

curl -L https://git.io/get_helm.sh | bash

墙原因, 上传我们给定的 get_helm.sh, chmod 700 然后./get_helm.sh

可能有文件格式兼容性问题, 用 vi 打开该 sh 文件, 输入:

:set ff

回车, 显示 fileformat=dos, 重新设置下文件格式:

:set ff=unix

保存退出:

:wq

# 上面地址被墙,这里去 github 下载 helm 压缩包
# 下载地址:https://github.com/helm/helm/releases?page=11

tar xf helm-v2.16.3-linux-amd64.tar.gz
cp linux-amd64/helm /usr/local/bin
cp linux-amd64/tiller /usr/local/bin

2. 验证版本 

helm version

3. 创建权限(master 执行)

创建 helm-rbac.yaml,写入如下内容

# 创建 helm-rbac.yaml 并写入内容
vi helm-rbac.yaml

# 给拥有者赋予读、写、执行权限
chmod 700 helm-rbac.yaml

# 应用配置
kubectl apply -f helm-rbac.yaml

 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

2.2.2.2 安装 Tiller(master 执行)

1. 初始化

helm init --service-account=tiller --tiller-image=jessestuart/tiller:v2.16.3 --history-max 300

--tiller-image 指定镜像, 否则会被墙。 大家使用这个镜像比较好 jessestuart/tiller:v2.16.3
等待节点上部署的 tiller 完成即可。

(1)报错信息,如下:

(2)报错原因:helm 仓库 URL 变更。

(3)解决方案,如下:

使用 --stable-repo-url参数指定新的仓库地址

helm init --service-account=tiller --tiller-image=jessestuart/tiller:v2.16.3 --history-max 300 --stable-repo-url https://charts.helm.sh/stable

注意:这里需要耐心等待,安装时间稍长。

验证,如下:

tiller

kubectl get pods --all-namespaces

2.2.2.3 安装 OpenEBS(master 执行)

https://kubesphere.io/docs/v2.1/zh-CN/appendix/install-openebs/

前提条件

  • 已有 Kubernetes 集群,并安装了 kubectl 或 Helm
  • Pod 可以被调度到集群的 master 节点(可临时取消 master 节点的 Taint)

关于第二个前提条件,是由于安装 OpenEBS 时它有一个初始化的 Pod 需要在 k8s-node1 节点启动并创建 PV(Persistent Volume) 给 KubeSphere 的有状态应用挂载。因此,若您的 k8s-node1 节点存在 Taint,建议在安装 OpenEBS 之前手动取消 Taint,待 OpenEBS 与 KubeSphere 安装完成后,再对 k8s-node1 打上 Taint,以下步骤供参考:

# 查看节点名称
kubectl get pod -o wide

# 确定 master 节点是否有 taint
kubectl describe node k8s-node1 | grep Taint

# 取消 taint
kubectl taint nodes k8s-node1 node-role.kubernetes.io/master:NoSchedule-

安装 OpenEBS 

 1. 创建 OpenEBS 的命名控件,OpenEBS 的相关资源将创建在这个 namespace 下:

# 创建 OpenEBS 的命名空间 openebs
kubectl create ns openebs

# 查看所有命名空间
kubectl get ns

2. 安装 OpenEBS,有以下两种方法,可参考其一进行创建:

A. 若集群已安装了 Helm,可通过 Helm 命令来安装 OpenEBS:【这里使用这个】

helm install --namespace openebs --name openebs stable/openebs --version 1.5.0

B. 除此之外 还可以通过 kubectl 命令安装:

kubectl apply -f https://openebs.github.io/charts/openebs-operator-1.5.0.yaml

3. 安装 OpenEBS 后将自动创建 4 个StorageClass,查看创建的 StorageClass:

kubectl get sc

4. 如下 将 openebs-hostpath 设置为默认的 StorageClass:

kubectl patch storageclass openebs-hostpath -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

5. 至此,OpenEBS 的 LocalPV 已作为默认的存储类型创建成功。由于在文档开头手动去掉了master 节点的 Taint,我们可以在安装完 OpenEBS 后将 master 节点 Taint 加上,避免业务相关的工作负载调度到 master 节点抢占 master 资源:

kubectl taint nodes k8s-node1 node-role.kubernetes.io=master:NoSchedule

2.2.3 最小化安装 kubesphere

在 Kubernetes 集群在线部署 KubeSphere

1. 若您的集群可用的资源符合 CPU > 1 Core, 可用内存 > 2 G, 可以参考以下命令开启

kubectl apply -f https://raw.githubusercontent.com/kubesphere/ks-installer/v2.1.1/kubesphere-minimal.yaml

2. 上面的地址无法访问,这里使用 kubesphere-mini.yaml 文件进行安装,如下:

# 创建 kubesphere-mini.yaml 文件
vi kubesphere-mini.yaml

# 应用 kubesphere-mini.yaml 文件,安装 kubesphere
kubectl apply -f kubesphere-mini.yaml

kubesphere-mini.yaml 具体内容,如下:

---
apiVersion: v1
kind: Namespace
metadata:
  name: kubesphere-system

---
apiVersion: v1
data:
  ks-config.yaml: |
    ---
    persistence:
      storageClass: ""
    etcd:
      monitoring: False
      endpointIps: 192.168.0.7,192.168.0.8,192.168.0.9
      port: 2379
      tlsEnable: True
    common:
      mysqlVolumeSize: 20Gi
      minioVolumeSize: 20Gi
      etcdVolumeSize: 20Gi
      openldapVolumeSize: 2Gi
      redisVolumSize: 2Gi
    metrics_server:
      enabled: False
    console:
      enableMultiLogin: False  # enable/disable multi login
      port: 30880
    monitoring:
      prometheusReplicas: 1
      prometheusMemoryRequest: 400Mi
      prometheusVolumeSize: 20Gi
      grafana:
        enabled: False
    logging:
      enabled: False
      elasticsearchMasterReplicas: 1
      elasticsearchDataReplicas: 1
      logsidecarReplicas: 2
      elasticsearchMasterVolumeSize: 4Gi
      elasticsearchDataVolumeSize: 20Gi
      logMaxAge: 7
      elkPrefix: logstash
      containersLogMountedPath: ""
      kibana:
        enabled: False
    openpitrix:
      enabled: False
    devops:
      enabled: False
      jenkinsMemoryLim: 2Gi
      jenkinsMemoryReq: 1500Mi
      jenkinsVolumeSize: 8Gi
      jenkinsJavaOpts_Xms: 512m
      jenkinsJavaOpts_Xmx: 512m
      jenkinsJavaOpts_MaxRAM: 2g
      sonarqube:
        enabled: False
        postgresqlVolumeSize: 8Gi
    servicemesh:
      enabled: False
    notification:
      enabled: False
    alerting:
      enabled: False
kind: ConfigMap
metadata:
  name: ks-installer
  namespace: kubesphere-system

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ks-installer
  namespace: kubesphere-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: ks-installer
rules:
- apiGroups:
  - ""
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - apps
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - extensions
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - batch
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - rbac.authorization.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - apiregistration.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - apiextensions.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - tenant.kubesphere.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - certificates.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - devops.kubesphere.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - monitoring.coreos.com
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - logging.kubesphere.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - jaegertracing.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - storage.k8s.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - admissionregistration.k8s.io
  resources:
  - '*'
  verbs:
  - '*'

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ks-installer
subjects:
- kind: ServiceAccount
  name: ks-installer
  namespace: kubesphere-system
roleRef:
  kind: ClusterRole
  name: ks-installer
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ks-installer
  namespace: kubesphere-system
  labels:
    app: ks-install
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ks-install
  template:
    metadata:
      labels:
        app: ks-install
    spec:
      serviceAccountName: ks-installer
      containers:
      - name: installer
        image: kubesphere/ks-installer:v2.1.1
        imagePullPolicy: "Always"

3. 查看安装日志,请耐心等待安装成功

kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f

打印结果:

Start installing monitoring
**************************************************
task monitoring status is successful
total: 1     completed:1
**************************************************
#####################################################
###              Welcome to KubeSphere!           ###
#####################################################

Console: http://10.0.2.15:30880
Account: admin
Password: P@88w0rd

NOTES:
  1. After logging into the console, please check the
     monitoring status of service components in
     the "Cluster Status". If the service is not
     ready, please wait patiently. You can start
     to use when all components are ready.
  2. Please modify the default password after login.

#####################################################

注意:这里 控制台的地址是 http://10.0.2.15:30880 ,访问 kubesphere 使用宿主机 ip 地址 http://192.168.56.100:30880 .

4. 当所有的 pod 都是 Running 状态则说明安装完成,浏览器才可以访问地址 http://192.168.56.100:30880

kubectl get pods --all-namespaces

访问:http://192.168.56.100:30880

Account: admin
Password: P@88w0rd

2.2.4 完整化安装【未做】

1. 若集群可用 CPU > 8 Core 且可用内存 > 16 G,可以使用以下命令完整安装 KubeSphere。

注意,应确保集群中有一个节点的可用内存大于 8 G。

kubectl apply -f https://raw.githubusercontent.com/kubesphere/ks-installer/v2.1.1/kubesphere-complete-setup.yaml

2. 查看滚动刷新的安装日志,请耐心等待安装成功。

kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f

说明:安装过程中若遇到问题,也可以通过以上日志命令来排查问题。 

3. 通过 kubectl get pod --all-namespaces查看 KubeSphere 相关 namespace 下所有 Pod 状态是否为 Running。确认 Pod 都正常运行后,可使用 IP:30880访问 KubeSphere UI 界面,默认的集群管理员账号为 admin/P@88w0rd。

2.2.5 安装可插拔的组件

节点扩容

        master节点只是一个调度系统,目前不需要扩容,pod存储都在node2、node3,所以要对node2、node3进行扩容,如下:

安装Metrics Server

        KubeSphere 支持用于部署的容器组(Pod)弹性伸缩程序 (HPA)。在 KubeSphere 中,Metrics Server 控制着 HPA 是否启用。您可以根据不同类型的指标(例如 CPU 和内存使用率,以及最小和最大副本数),使用 HPA 对象对部署 (Deployment) 自动伸缩,当业务需求增加时,KubeSphere 能够无缝地自动水平增加 Pod 数量,提高应用系统的稳定性。通过这种方式,HPA 可以帮助确保您的应用程序在不同情况下都能平稳、一致地运行。

        关于如何使用 HPA 请参考 设置弹性伸缩,注意,Installer 默认最小化安装因此初始安装时并未开启 Metrics-server 的安装,请在使用 HPA 之前开启 Metrics-server 的安装,参考以下文档。

安装后如何启用 Metrics Server

1. 通过修改 ks-installer 的 configmap 可以选装组件,执行以下命令。

kubectl edit cm -n kubesphere-system ks-installer

参考如下修改 :

...
   devops:
      enabled: True # 开启自动化部署
      jenkinsMemoryLim: 2Gi
      jenkinsMemoryReq: 1000Mi # jenkins初始化申请调整为1G
      jenkinsVolumeSize: 8Gi
      jenkinsJavaOpts_Xms: 512m
      jenkinsJavaOpts_Xmx: 512m
      jenkinsJavaOpts_MaxRAM: 2g
      sonarqube:
        enabled: False # 开启代码质量检查
        postgresqlVolumeSize: 8Gi
    servicemesh:
      enabled: True
    notification:
      enabled: True # 打开通知系统
    alerting:
      enabled: True # 打开告警系统
...

2.  保存退出,保存退出,参考 验证可插拔功能组件安装 ,通过查询 ks-installer 日志或 Pod 状态验证功能组件是否安装成功。

(1)在 kubectl 中执行以下命令查看安装日志检查安装过程。

开启可插拔功能组件的安装后,需要通过日志或 Pod 状态验证功能组件是否安装成功。

查看 ks-installer 安装过程中产生的动态日志,等待安装成功:

kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f

当日志出现以下提示,说明开启的组件已安装成功。

(2)安装成功后,可登陆控制台,在 服务组件下查看可插拔功能组件下的所有组件是否都已经安装启动完毕。

3. 验证组件的安装 

        除了在控制台查看组件状态,还可以通过 kubectl 命令确认可插拔的组件是否安装成功。
通常情况下,当该 namespace 下的所有 Pod 状态都为 Running,并且 Job 都为 Completed 状态,则说明该组件安装成功。

kubectl get pods --all-namespaces

2.3 建立多租户系统

官方文档:创建企业空间、项目、用户和平台角色

2.3.1 目的

        本文档面向初次使用 KubeSphere 的集群管理员用户,引导新手用户创建企业空间、创建新的角色和账户,然后邀请新用户进入企业空间后,创建项目和 DevOps 工程,帮助用户熟悉多租户下的用户和角色管理,快速上手 KubeSphere。

2.3.2 前提条件

        已安装 KubeSphere,并使用默认的 admin 用户名和密码登录了 KubeSphere。

        目前,平台的资源一共有三个层级,包括 集群 (Cluster)、 企业空间 (Workspace)、 项目 (Project) 和 DevOps Project (DevOps 工程),层级关系如下图所示,即一个集群中可以创建多个企业空间,而每个企业空间,可以创建多个项目和 DevOps工程,而集群、企业空间、项目和 DevOps工程中,默认有多个不同的内置角色。

2.3.3 集群管理员

第一步:创建角色和账号

平台中的 cluster-admin 角色可以为其他用户创建账号并分配平台角色,平台内置了集群层级的以下三个常用的角色,同时支持自定义新的角色。

内置角色 描述
cluster-admin 集群管理员,可以管理集群中所有的资源。
workspaces-manager 集群中企业空间管理员,仅可创建、删除企业空间,维护企业空间中的成员列表。
cluster-regular 集群中的普通用户,在被邀请加入企业空间之前没有任何资源操作权限。

通过下图可以更清楚地了解本示例的逻辑:

本示例首先新建一个角色(users-manager) ,为该角色授予账号管理、角色管理权限,然后新建一个账号并给这个账号授予 users-manager 角色。

账号名 集群角色 职责
user-manager users-manager 管理集群的账户和角色

1. 点击 平台管理-》平台角色-》创建,创建一个角色用于管理所有的账户和角色。

2. 填写平台角色的基本信息。

  • 名称:角色的名称。
  • 描述信息:简单描述角色拥有的权限。

3. 为创建的平台角色进行权限设置,勾选账户管理、角色管理的所有权限后,点击创建。

4. 点击 平台管理-》账户管理-》创建。

5. 填写新用户的基本信息,如用户名 atguigu-hr ,角色选择 user-manager ,其它信息可自定义,点击确定。

6. 使用新创建的用户 atguigu-hr 登录。

7. 使用 atguigu-hr 账户登录来创建下表中的四个账号,ws-manager 将用于创建一个企业空间,并指定 ws-admin 作为企业空间管理员。切换 atguigu-hr 账号登录后在账号管理下,新建四个账号,创建步骤同上,参考如下信息创建。

用户名 集群角色 职责
ws-manager workspaces-manager 创建企业空间
ws-admin cluster-regular 管理企业空间下所有的资源(本示例用于邀请新成员加入企业空间)
project-admin cluster-regular 创建和管理项目、DevOps工程,邀请新成员加入
project-regular cluster-regular 将被 project-admin 邀请加入项目和DevOps工程,用于创建项目和工程下的工作负载、Pipeline等资源

8. 查看新建的四个账号信息。

2.3.4 企业空间管理员

第二步:创建企业空间

企业空间 (workspace) 是 KubeSphere 实现多租户模式的基础,是用户管理项目、DevOps 工程和企业成员的基本单位。

1. 使用 ws-manager 登录 KubeSphere ,ws-manager 有权限查看和管理平台的所有企业空间。

点击 平台管理-》企业空间,可见新安装的环境只有一个系统默认的企业空间 system-workspace,用于运行 KubeSphere 平台相关组件和服务,禁止删除该企业空间。

点击创建,创建新的企业空间:

2. 填写企业空间基本信息,点击确定。企业空间的创建者同时默认为该企业空间的管理员(workspaces-manager),拥有企业空间的最高管理权限。

  • 企业空间名称:请尽量保持企业名称简短,便于用户浏览和搜索,本示例是 gulimall-workspace。
  • 企业空间管理员:指定 ws-manager 为管理员,同时邀请 ws-manager 用户进入该企业空间。
  • 描述信息:简单介绍该企业空间。

3. 邀请成员到该企业空间,点击 企业空间设置-》企业成员,选择企业空间成员并赋予角色。

成员 企业角色 描述
ws-admin workspace-admin 企业空间管理员,可以管理企业空间下所有的资源

新创建的企业空间,默认有三个内置企业角色,如下:

4. 切换 ws-admin(企业空间gulimall-workspace的管理员)登录,点击 进入企业空间。

5. ws-admin可以从集群成员中邀请新成员加入当前企业空间,然后创建项目和 DevOps 工程。点击 企业空间设置-》企业成员-》邀请成员。

这一步需要邀请在 2.3.3 的步骤6创建的两个用户 project-admin和 project-regular进入企业空间,且分别授予 workspace-regular和 workspace-viewer的角色,此时该企业空间一共有如下四个用户:

用户名 企业角色 职责
ws-admin workspace-admin 企业空间管理员,管理企业空间下所有的资源(本示例用于邀请新成员加入企业空间)。
project-admin workspace-regular 创建和管理项目、DevOps 工程。
project-regular workspace-viewer 企业空间的观察者,可以查看企业空间下所有的资源信息。

2.3.5 项目和 DevOps 工程管理员

第三步:创建项目

创建工作负载、服务和 CI/CD 流水线等资源之前,需要预先创建项目和 DevOps 工程。

1. 使用 project-admin 登录,进入 gulimall-workspace ,点击 创建-》创建资源型项目。

2. 填写项目的基本信息和高级设置,完成后点击 下一步。

基本信息

  • 名称:为项目起一个简洁明了的名称,便于用户浏览和搜索,比如 demo-project
  • 别名:帮助您更好的区分资源,并支持中文名称,比如 示例项目
  • 描述信息:简单介绍该项目

高级信息

此处将默认的最大 CPU 和内存分别设置 0.5 Core和 500 Mi,后续的示例都可以在这个示例项目中完成,在项目使用过程中可根据实际情况再次编辑资源默认请求。

完成高级设置后,点击创建。

说明:高级设置是在当前项目中配置容器默认的 CPU 和内存的请求与限额,相当于是给项目创建了一个 Kubernetes 的 LimitRange 对象,在项目中创建工作负载后填写容器组模板时,若不填写容器 CPU 和内存的请求与限额,则容器会被分配在高级设置的默认 CPU 和内存请求与限额值。

3. 邀请成员

project-admin 创建完项目 gulimall 后,点击 项目成员-》邀请成员,将用户 project-regular 邀请进gulimall 项目并赋予 operator(项目维护者权限) 角色权限,作为该项目的开发人员。

第四步:创建 DevOps工程

DevOps 提供一系列持续集成 (CI) 和持续交付 (CD) 工具,可以使 IT 和软件开发团队之间的流程实现自动化。在 CI/CD 工作流中,每次集成都通过自动化构建来验证,包括编码、发布和测试,从而帮助开发者提前发现集成错误,团队也可以快速、安全、可靠地将内部软件交付到生产环境。

1. 继续使用 project-admin 用户创建 DevOps 工程。点击创建,在弹窗中选择创建一个DevOps 工程。DevOps 工程的创建者 project-admin 将默认成为该工程的 owner,拥有 DevOps 工程的最高权限。

2. 输入 DevOps 工程的名称和描述信息,如下,点击 创建。

  • 名称:此 DevOps 项目的简明名称,便于用户识别,例如 demo-devops
  • 描述信息:此 DevOps 项目的简要介绍。

3. 点击 DevOps 工程列表中的 gulimall-devops 进入工程,邀请成员到此工程,并赋予 maintainer 角色权限,用于工程的 Pipeline配置、凭证配置等操作。具体操作步骤如下,后续在 DevOps 工程中创建 Pipeline 和凭证等资源,都可以由 project-regular用户登录后进行操作。

创建工程默认有四种角色,如下:

2.4 创建 WordPress 应用并发布至 Kubernetes

官方文档:创建并部署 WordPress

非官方文档:快速入门 - 3. 创建 Wordpress 应用并发布至 K8s - 《KubeSphere v2.1 使用手册》 - 书栈网 · BookStack

2.4.1 WordPress 简介

        WordPress 是使用 PHP 开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的环境中架设属于自己的网站。本文以创建一个 Wordpress 应用 为例,以创建 KubeSphere 应用的形式将 Wordpress 的组件(MySQL 和 Wordpress)创建后发布至 Kubernetes 中,并在集群外访问 Wordpress 服务。

一个完整的 Wordpress 应用会包括以下 Kubernetes 对象,其中 MySQL 作为后端数据库,Wordpress 本身作为前端提供浏览器访问。

2.4.2 前提条件

       已创建了企业空间、项目和普通用户 project-regular 账号(该已账号已被邀请至示例项目),并开启了外网访问,请参考 多租户管理快速入门

2.4.3 创建密钥

2.4.3.1 创建 MySQL 密钥

1. 以项目普通用户 project-regular 登录 KubeSphere ,在当前项目下左侧菜单栏的 配置中心 选择   密钥,点击 创建

2. 填写密钥的基本信息,完成后点击 下一步。

  • 名称:作为 MySQL 容器中环境变量的名称,可自定义,例如 mysql-secret 

  • 别名:别名可以由任意字符组成,帮助您更好的区分资源,例如 MySQL 密钥

  • 描述信息:简单介绍该密钥,如 MySQL 初始密码

3. 密钥设置,填写如下信息,完成后点击 创建。

  • 类型:选择 默认(Opaque)
  • Data:Data 键值对填写 MYSQL_ROOT_PASSWORD123456(对应MySQL环境变量)

4. 可以点击密钥,查看密钥的信息。

2.4.3.2 创建 WordPress 密钥

同上,创建一个 WordPress 密钥,Data 键值对填写 WORDPRESS_DB_PASSWORD123456 。此时两个密钥都创建完成。

2.4.4 创建存储卷

1. 在当前项目下左侧菜单栏的 存储卷,点击 创建,基本信息如下。

  • 名称:wordpress-pvc
  • 别名:Wordpress 持久化存储卷

2. 完成后点击 下一步,存储类型默认 openebs-hostpath,访问模式和存储卷容量也可以使用默认值,点击 下一步,直接创建即可。

3. 同样的方法创建mysql存储卷

2.4.5 创建应用

前置条件

        目前 docker hub 已经不允许访问,在添加容器镜像无法从官网下载镜像,这里我们使用 Docker 搭建 Harbor 私有仓库,便于 Kubesphere 集成容器镜像仓库。Docker 搭建 Harbor 私有仓库,请参考博客:Docker 搭建 Harbor 私有仓库-CSDN博客

注意:创建一个新的虚拟机 harbor(192.168.56.103),保证集群的三个节点k8s-node1、k8s-node2、k8s-node3 都能 ping 通 harbor,并且集群的三个节点都要添加 Harbor 地址到信任列表,如下:

# 编辑 Docker 配置文件
vi /etc/docker/daemon.json

# 添加内容如下

{
  "insecure-registries": ["192.168.56.103:80"]
}

# 保存
:wq

# 重新加载 Docker 配置,并重启
systemctl daemon-reload
systemctl restart docker

添加 Harbor 镜像仓库

1. 登录 KubeSphere 管理控制台,在已创建的项目中,左侧菜单栏中选择 配置中心 -> 密钥,点击创建。

2. 填写镜像仓库的基本信息。

  • 名称:为镜像仓库起一个简洁明了的名称,便于浏览和搜索。
  • 别名:帮助您更好的区分资源,并支持中文名称。
  • 描述信息:简单介绍镜像仓库的主要特性,让用户进一步了解该镜像仓库。

3. 密钥设置,选择类型 镜像仓库密钥,填写登录镜像仓库的信息。

  • 仓库地址:使用 Harbor 仓库地址 192.168.56.103:80 
  • 用户名/密码:admin/Harbor12345。
  • 邮箱:填写个人邮箱。

4. 点击创建并查看结果。

2.4.5.1 添加 MySQL 后端组件 

1. 在左侧菜单栏选择 应用负载->应用,点击部署新应用。

2. 填写基本信息,完成后在右侧点击 添加组件

  • 应用名称:必填,起一个简洁明了的名称,便于用户浏览和搜索,例如填写 wordpress-application
  • 描述信息:简单介绍该工作负载,方便用户进一步了解。

3. 填写 MySQL 组件信息。

  • 名称:mysql。
  • 组件版本:v1。
  • 别名:MySQL数据库。
  • 负载类型:有状态服务(有状态副本集)。

4. 点击添加 容器镜像,镜像填写 gulimall/mysql:5.6(应指定镜像版本号),然后回车,点击使用默认端口。

注意:

  • DockerHub官网无法使用,这里我们使用自己私有的镜像仓库:192.168.56.103:80/gulimall
  • 在高级设置中确保内存限制 ≥ 1000 Mi,否则可能 MySQL 会因内存 Limit 不够而无法启动。

5. 下滑,勾选 环境变量,然后选择 引用配置文件或密钥,名称填写为 MYSQL_ROOT_PASSWORD ,下拉框中选择密钥 mysql-secret 和  MYSQL_ROOT_PASSWORD 。完成后点击右下角 √ 。

6. 点击 添加存储卷模板 ,为 MySQL 创建一个 PVC 实现数据持久化。

参考下图填写存储卷信息:

  • 存储卷名称:必填,起一个简洁明了的名称,便于用户浏览和搜索,此处填写 mysql-pvc
  • 存储类型:选择集群已有的存储类型,如 openebs-hostpath
  • 访问模式和容量:访问模式默认 RWO ,容量默认 10Gi
  • 挂载路径:存储卷在容器内的挂载路径,选择 读写,路径填写 /var/lib/mysql

完成后点击右下角 √ 。

2.4.5.2 添加 WordPress 前端组件

1. 填写 WordPress 组件信息。

  • 名称:wordpress。
  • 组件版本:v1。
  • 别名:WordPress 前端。
  • 负载类型:无状态服务(部署)。

2. 点击添加 容器镜像,镜像填写 gulimall/wordpress:4.8-apache(应指定镜像版本号),然后回车,点击使用默认端口。

3. 下滑,勾选 环境变量,这里需要添加两个环境变量。

  • 点击 引用配置文件或密钥,名称填写为 WORDPRESS_DB_PASSWORD,下拉选择密钥 wordpress-secret 和 WORDPRESS_DB_PASSWORD
  • 点击 添加环境变量,名称填写为 WORDPRESS_DB_HOST,值填写为 mysql ,对应的是上一步添加 MySQL 组件的服务名称,否则无法连接 MySQL 数据库。

完成后点击右下角 √ 。

4. 点击 添加存储卷,选择已有存储卷 wordpress-pvc,访问模式改为 读写,容器挂载路径 /var/www/html完成后点击右下角 √ 。

5. 点击 创建。

2.4.5.3 查看应用资源

1. 在 工作负载 下查看 部署有状态副本集 的状态,当它们都显示为 运行中,说明 WordPress 应用创建成功。

 2. 选择左侧导航栏中的应用负载 -> 服务。点击 wordpress 右侧的三个点后,选择编辑外部访问,选择 NodePort,点击 确定。

2.4.5.4 访问 wordpress

访问地址:http://192.168.56.100:31285

1. 选择 简体中文。

2. 注册信息,并点击安装 WordPress。

3. 安装完成,进行登录。

  • 用户名/电子邮箱地址:www/atguigu-wordpress@atguigu.com
  • 密码:123456

4. 登录成功页面。

3 DevOps

3.1 项目开发需要考虑的维度

Dev:怎么开发?

Ops:怎么运维?

高并发:怎么承担高并发

高可用:怎么做到高可用

3.2 什么是 DevOps

微服务,服务自治。

DevOps:Development 和 Operations 的组合

  • DevOps 看作开发(软件工程)、技术运营和质量保障(QA)三者的交集。
  • 突出重视软件开发人员和运维人员的沟通合作,通过自动化流程来使得软件构建、测试、发布更加快捷、频繁和可靠。
  • DevOps 希望做到的是软件产品交付过程中 IT 工具链的打通,使得各个团队减少时间损耗,更加高效地协同工作。专家们总结出了下面这个 DevOps 能力图,良好的闭环可以大大增加整体的产出。

3.3 什么是 CI&CD

3.3.1 持续集成(Continuous Integration)

  • 持续集成是指软件个人研发的部分向软件整体部分交付,频繁进行集成以便更快地发现其中的错误。“持续集成”源自于极限编程(XP),是 XP 最初的 12 种实践之一。
  • CI 需要具备这些:
    • 全面的自动化测试。这是实践持续集成&持续部署的基础,同时,选择合适的 自动化测试工具也极其重要;
    • 灵活的基础设施。容器,虚拟机的存在让开发人员和 QA 人员不必再大费周折;
    • 版本控制工具。如 Git,CVS,SVN 等;
    • 自动化的构建和软件发布流程的工具。如 Jenkins,flow.ci;
    • 反馈机制。如构建/测试的失败,可以快速地反馈到相关负责人,以尽快解决达到一个更稳定的版本。

3.3.2 持续交付(Continuous Delivery)

持续交付在持续集成的基础上, 将集成后的代码部署到更贴近真实运行环境的「类生产环境」 (production-like environments) 中。 持续交付优先于整个产品生命周期的软件部署, 建立 在高水平自动化持续集成之上。

灰度发布。

持续交付和持续集成的优点非常相似:

  • 快速发布。 能够应对业务需求, 并更快地实现软件价值。
  • 编码->测试->上线->交付的频繁迭代周期缩短, 同时获得迅速反馈;
  • 高质量的软件发布标准。 整个交付过程标准化、 可重复、 可靠,
  • 整个交付过程进度可视化, 方便团队人员了解项目成熟度;
  • 更先进的团队协作方式。 从需求分析、 产品的用户体验到交互 设计、 开发、 测试、 运 维等角色密切协作, 相比于传统的瀑布式软件团队, 更少浪费。

3.3.3 持续部署(Continuous Deployment)

持续部署是指当交付的代码通过评审之后,自动部署到生产环境中。持续部署是持续交付的最高阶段。这意味着,所有通过了一系列的自动化测试的改动都将自动部署到生产环境。它也可以被称为“Continuous Release”。

“开发人员提交代码,持续集成服务器获取代码,执行单元测试,根据测试结果决定是否部署到预演环境,如果成功部署到预演环境,进行整体验收测试,如果测试通过,自动部署到产品环境,全程自动化高效运转。“

持续部署主要好处是,可以相对独立地部署新的功能,并能快速地收集真实用户的反馈。

“You build it, you run it”,这是 Amazon 一年可以完成 5000 万次部署, 平均每个工程师每天部署超过 50 次的核心秘籍。

下图是由 Jams Bowman 绘制的持续交付工具链图

3.3.4 落地方案

Maven+Github+Jenkins(Hudson[现由甲骨文维护]) +Docker

自动化部署

3.4 基于Sping Boot项目构建流水线

官方文档:使用 Jenkinsfile 创建流水线

非官方文档:快速入门 - 9. 基于Spring Boot项目构建流水线 - 《KubeSphere v2.1 使用手册》 - 书栈网 · BookStack

        Jenkinsfile in SCM 意为将 Jenkinsfile 文件本身作为源代码管理 (Source Control Management) 的一部分,根据该文件内的流水线配置信息快速构建工程内的 CI/CD 功能模块,比如阶段 (Stage),步骤 (Step) 和任务 (Job)。因此,在代码仓库中应包含 Jenkinsfile。

3.4.1 目的

        本示例演示如何通过 GitHub 仓库中的 Jenkinsfile 来创建流水线,流水线共包括 8 个阶段,最终将演示示例部署到 KubeSphere 集群中的开发环境和生产环境且能够通过公网访问。仓库中的 dependency 分支为缓存测试用例,测试方式与 master 分支类似,对 dependency 的多次构建可体现出利用缓存可以有效的提升构建速度。

3.4.2 前提条件

  • 开启安装了 DevOps 功能组件,参考 安装 DevOps 系统
  • 本示例以 GitHub 和 DockerHub 为例,参考前确保已创建了 GitHub 和 DockerHub 账号;
  • 已创建了企业空间和 DevOps 工程并且创建了项目普通用户 project-regular 的账号,若还未创建请参考 多租户管理快速入门
  • 使用项目管理员 project-admin 邀请项目普通用户 project-regular 加入 DevOps 工程并授予 maintainer 角色,若还未邀请请参考 多租户管理快速入门 - 邀请成员
  • 参考 配置 ci 节点 为流水线选择执行构建的节点。

3.4.3 流水线概览

下面的流程图简单说明了流水线完整的工作过程:

流程说明:

  • 阶段一. Checkout SCM: 拉取 GitHub 仓库代码
  • 阶段二. Unit test: 单元测试,如果测试通过了才继续下面的任务
  • 阶段三. SonarQube analysis:sonarQube 代码质量检测
  • 阶段四. Build & push snapshot image: 根据行为策略中所选择分支来构建镜像,并将 tag 为 SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER 推送至 Harbor (其中 $BUILD_NUMBER 为 pipeline 活动列表的运行序号)。
  • 阶段五. Push latest image: 将 master 分支打上 tag 为 latest,并推送至 DockerHub。
  • 阶段六. Deploy to dev: 将 master 分支部署到 Dev 环境,此阶段需要审核。
  • 阶段七. Push with tag: 生成 tag 并 release 到 GitHub,并推送到 DockerHub。
  • 阶段八. Deploy to production: 将发布的 tag 部署到 Production 环境。

3.4.4 创建凭证

注意:

  • GitHub 账号或密码带有 "@" 这类特殊字符,需要创建凭证前对其进行 urlencode 编码,可通过一些 第三方网站进行转换,然后再将转换后的结果粘贴到对应的凭证信息中。
  • 这里需要创建的是凭证(Credential),不是密钥(Secret)。

在 多租户管理快速入门 中已给项目普通用户 project-regular 授予了 maintainer 的角色,因此使用 project-regular 登录 KubeSphere,进入已创建的 devops-demo 工程,开始创建凭证。

1、本示例代码仓库中的 Jenkinsfile 需要用到 DockerHub、GitHub 和 kubeconfig (kubeconfig 用于访问接入正在运行的 Kubernetes 集群) 等一共 3 个凭证 (credentials) ,参考 创建凭证 依次创建这三个凭证。

2、然后参考 访问 SonarQube 并创建 Token,创建一个 Java 的 Token 并复制。

3、最后在 KubeSphere 中进入 gulimall-devops 的 DevOps 工程中,与上面步骤类似,在 凭证 下点击 创建,创建一个类型为 秘密文本 的凭证,凭证 ID 命名为 sonar-token,密钥为上一步复制的 token 信息,完成后点击 确定

  • 创建 Harbor 凭证

        创建一个用于 Harbor 登录的凭证,凭证 ID 为:harbor-id,类型选择 账户凭证。用户名/密码:admin/Harbor12345,完成后点击 确定。

  • 创建 GitHub 凭证

        同上,创建一个用于 GitHub 的凭证,凭证 ID 为:github-id,类型选择 账户凭证,输入您个人的 GitHub 用户名和密码,备注描述信息,完成后点击 确定。

注意:github 的认证策略发生了改变,在 2021年8月13日的时候,用户名加密码的认证方式被去掉了,换成了 个人令牌(Personal Access Token)的校验方式。所以我们这里使用token
创建token的具体操作步骤可以参考文档:GIthub获取token令牌_github token在哪里-CSDN博客

  • 创建 kubeconfig 凭证

        在 凭证 下点击 创建,创建一个类型为 kubeconfig 的凭证,凭证 ID 可命名为 demo-kubeconfig,完成后点击 确定。

说明:kubeconfig 类型的凭证用于访问接入正在运行的 Kubernetes 集群,在流水线部署步骤将用到该凭证。注意,此处的 Content 将自动获取当前 KubeSphere 中的 kubeconfig 文件内容,若部署至当前 KubeSphere 中则无需修改,若部署至其它 Kubernetes 集群,则需要将其 kubeconfig 文件的内容粘贴至 Content 中。

        KubeSphere内置SonarQube,我们通过 kubectl get svc --all-namespaces 命令,找到 SonarQube 服务,可以看到端口信息。

kubectl get svc --all-namespaces

访问地址:http://192.168.56.100:32595

账号:admin

密码:admin

ded383e8a4e3deedc8efac2cd87c348b0649ff30

创建 SonarQube 凭证

3.4.5 修改 Jenkinsfile

3.4.5.1 第一步:Fork项目

登录 GitHub,将本示例用到的 GitHub 仓库 devops-java-sample Fork 至您个人的 GitHub。

3.4.5.2 修改 Jenkinsfile

1. Fork 至您个人的 GitHub 后,在 根目录 进入 Jenkinsfile-online

2. 在 GitHub UI 点击编辑图标,需要修改如下环境变量 (environment) 的值。

修改项 含义
DOCKER_CREDENTIAL_ID dockerhub-id 填写创建凭证步骤中的 DockerHub 凭证 ID,用于登录您的 DockerHub
GITHUB_CREDENTIAL_ID github-id 填写创建凭证步骤中的 GitHub 凭证 ID,用于推送 tag 到 GitHub 仓库
KUBECONFIG_CREDENTIAL_ID demo-kubeconfig kubeconfig 凭证 ID,用于访问接入正在运行的 Kubernetes 集群
REGISTRY docker.io 默认为 docker.io 域名,用于镜像的推送
DOCKERHUB_NAMESPACE your-dockerhub-account 替换为您的 DockerHub 账号名 (它也可以是账户下的 Organization 名称)
GITHUB_ACCOUNT your-github-account 替换为您的 GitHub 账号名,例如 https://github.com/kubesphere/ 则填写 kubesphere (它也可以是账户下的 Organization 名称)
APP_NAME devops-java-sample 应用名称
SONAR_CREDENTIAL_ID sonar-token 填写创建凭证步骤中的 SonarQube token凭证 ID,用于代码质量检测

修改后的内容:

 environment {
        DOCKER_CREDENTIAL_ID = 'harbor-id'
        GITHUB_CREDENTIAL_ID = 'github-id'
        KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
        REGISTRY = '192.168.56.103:80/gulimall'
        DOCKERHUB_NAMESPACE = 'admin'
        GITHUB_ACCOUNT = 'good0luck'
        APP_NAME = 'devops-java-sample'
        SONAR_CREDENTIAL_ID = 'sonar-token'
    }

注:master分支 Jenkinsfile 中 mvn命令的参数 -o,表示开启离线模式。本示例为适应某些环境下网络的干扰,以及避免在下载依赖时耗时太长,已事先完成相关依赖的下载,默认开启离线模式。

3. 修改以上的环境变量后,点击 Commit changes,将更新提交到当前的 master 分支。

3.4.6 创建项目

CI/CD 流水线会根据示例项目的 yaml 模板文件,最终将示例分别部署到 kubesphere-sample-devkubesphere-sample-prod 这两个项目 (Namespace) 环境中,这两个项目需要预先在控制台依次创建,参考如下步骤创建该项目。

一个项目对应一个Namespace 。

3.4.6.1 创建第一个项目

提示:项目管理员 project-admin 账号已在 多租户管理快速入门 中创建。

1. 使用项目管理员 project-admin 账号登录 KubeSphere,在之前创建的企业空间 (gulimall-workspace) 下,点击 项目创建,创建一个 资源型项目,作为本示例的开发环境,填写该项目的基本信息,完成后点击 下一步

  • 名称:固定为 kubesphere-sample-dev,若需要修改项目名称则需在 yaml 模板文件 中修改 namespace
  • 别名:可自定义,比如 开发环境
  • 描述信息:可简单介绍该项目,方便用户进一步了解

2. 本示例暂无资源请求和限制,因此高级设置中无需修改默认值,点击 创建,项目可创建成功。

3. 邀请成员

第一个项目创建完后,还需要项目管理员 project-admin 邀请当前的项目普通用户 project-regular 进入 kubesphere-sample-dev 项目,进入「项目设置」→「项目成员」,点击「邀请成员」选择邀请 project-regular 并授予 operator 角色,若对此有疑问可参考 多租户管理快速入门 - 邀请成员。

3.4.6.2 创建第二个项目

同上,参考以上两步创建一个名称为 kubesphere-sample-prod 的项目作为生产环境,并邀请普通用户 project-regular 进入 kubesphere-sample-prod 项目并授予 operator 角色。

说明:当 CI/CD 流水线后续执行成功后,在 kubesphere-sample-dev 和 kubesphere-sample-prod 项目中将看到流水线创建的部署 (Deployment) 和服务 (Service)。

3.4.7 创建流水线

3.4.7.1 第一步:填写基本信息

1. 使用 project-regular 登录,进入已创建的 DevOps 工程,选择左侧菜单栏的 流水线,然后点击创建

2. 在弹出的窗口中,输入流水线的基本信息。

  • 名称:为创建的流水线起一个简洁明了的名称,便于理解和搜索
  • 描述信息:简单介绍流水线的主要特性,帮助进一步了解流水线的作用
  • 代码仓库:点击选择代码仓库,代码仓库需已存在 Jenkinsfile

3.4.7.2 第二步:添加仓库

1. 点击代码仓库,以添加 Github 仓库为例。

2. 点击弹窗中的 获取 Token

3. 在GitHub 的 access token 页面填写 Token description,简单描述该 token,如 DevOps demo,在 Select scopes 中无需任何修改,点击 Generate token,GitHub 将生成一串字母和数字组成的 token 用于访问当前账户下的 GitHub repo。

4. 复制生成的 token,在 KubeSphere Token 框中输入该 token 然后点击保存。

5. 验证通过后,右侧会列出此 Token 关联用户的所有代码库,选择其中一个带有 Jenkinsfile 的仓库。比如此处选择准备好的示例仓库 devops-java-sample,点击 选择此仓库,完成后点击 下一步。

3.4.7.3 第三步:高级设置

完成代码仓库相关设置后,进入高级设置页面,高级设置支持对流水线的构建记录、行为策略、定期扫描等设置的定制化,以下对用到的相关配置作简单释义。

1. 分支设置中,勾选 丢弃旧的分支,此处的 保留分支的天数 和 保留分支的最大个数 默认为 -1。

说明:

分支设置的保留分支的天数和保持分支的最大个数两个选项可以同时对分支进行作用,只要某个分支的保留天数和个数不满足任何一个设置的条件,则将丢弃该分支。假设设置的保留天数和个数为 2 和 3,则分支的保留天数一旦超过 2 或者保留个数超过 3,则将丢弃该分支。默认两个值为 -1,表示将会丢弃已经被删除的分支。

丢弃旧的分支将确定何时应丢弃项目的分支记录。分支记录包括控制台输出,存档工件以及与特定分支相关的其他元数据。保持较少的分支可以节省 Jenkins 所使用的磁盘空间,我们提供了两个选项来确定应何时丢弃旧的分支:

  • 保留分支的天数:如果分支达到一定的天数,则丢弃分支。
  • 保留分支的个数:如果已经存在一定数量的分支,则丢弃最旧的分支。

2. 行为策略中,KubeSphere 默认添加了三种策略。由于本示例还未用到 从 Fork 仓库中发现 PR 这条策略,此处可以删除该策略,点击右侧删除按钮。

3. 默认的 脚本路径 为 Jenkinsfile,请将其修改为 Jenkinsfile-online

注:路径是 Jenkinsfile 在代码仓库的路径,表示它在示例仓库的根目录,若文件位置变动则需修改其脚本路径。

4. 在 扫描 Repo Trigger 勾选 如果没有扫描触发,则定期扫描,扫描时间间隔可根据团队习惯设定,本示例设置为 5 minutes。 

说明:定期扫描是设定一个周期让流水线周期性地扫描远程仓库,根据 行为策略 查看仓库有没有代码更新或新的 PR。

Webhook 推送:

Webhook 是一种高效的方式可以让流水线发现远程仓库的变化并自动触发新的运行,GitHub 和 Git (如 Gitlab) 触发 Jenkins 自动扫描应该以 Webhook 为主,以上一步在 KubeSphere 设置定期扫描为辅。在本示例中,可以通过手动运行流水线,如需设置自动扫描远端分支并触发运行,详见 设置自动触发扫描 - GitHub SCM

5. 将 webhook推送地址 复制到Github仓库 setting->webhook->Add webhook,填写复制的地址到Payload URL,点击 Add webhook 进行保存。

6. 完成高级设置后点击 创建

3.4.7.4 第四步:运行流水线

流水线创建后,点击浏览器的 刷新 按钮,可见两条自动触发远程分支后的运行记录,分别为 master 和 dependency 分支的构建记录。

1. 点击右侧 运行,将根据上一步的 行为策略 自动扫描代码仓库中的分支,在弹窗选择需要构建流水线的 master 分支,系统将根据输入的分支加载 Jenkinsfile-online (默认是根目录下的 Jenkinsfile)。

2. 由于仓库的 Jenkinsfile-online 中 TAG_NAME: defaultValue 没有设置默认值,因此在这里的 TAG_NAME 可以输入一个 tag 编号,比如输入 v0.0.1。

3. 点击 确定,将新生成一条流水线活动开始运行。

说明: tag 用于在 Github 和DockerHub 中分别生成带有 tag 的 release 和镜像。 注意: 在主动运行流水线以发布 release 时,TAG_NAME 不应与之前代码仓库中所存在的 tag 名称重复,如果重复会导致流水线的运行失败。

至此,流水线 已完成创建并开始运行。

注:点击 分支 切换到分支列表,查看流水线具体是基于哪些分支运行,这里的分支则取决于上一步 行为策略 的发现分支策略。

3.4.7.5 第五步:审核流水线

为方便演示,此处默认用当前账户来审核,当流水线执行至 input 步骤时状态将暂停,需要手动点击 继续,流水线才能继续运行。注意,在 Jenkinsfile-online 中分别定义了三个阶段 (stage) 用来部署至 Dev 环境和 Production 环境以及推送 tag,因此在流水线中依次需要对 deploy to dev, push with tag, deploy to production 这三个阶段审核 3 次,若不审核或点击 终止 则流水线将不会继续运行。

说明:在实际的开发生产场景下,可能需要更高权限的管理员或运维人员来审核流水线和镜像,并决定是否允许将其推送至代码或镜像仓库,以及部署至开发或生产环境。Jenkinsfile 中的 input步骤支持指定用户审核流水线,比如要指定用户名为 project-admin 的用户来审核,可以在 Jenkinsfile 的 input 函数中追加一个字段,如果是多个用户则通过逗号分隔,如下所示:

···
input(id: 'release-image-with-tag', message: 'release image with tag?', submitter: 'project-admin,project-admin1')
···

3.4.8 查看流水线

流水线这里有点问题,未解决,可能是私服、网络等问题。可参照如下网址操作:

快速入门 - 9. 基于Spring Boot项目构建流水线 - 《KubeSphere v2.1 使用手册》 - 书栈网 · BookStack

         


网站公告

今日签到

点亮在社区的每一天
去签到