云原生与k8s集群构建全过程
作者:fengchengwu2012
一、云原生和kubernetes
1、云原生的概念
云是和本地相对的,传统的应用必须跑在本地服务器上,现在流行的应用都跑在云端,云包含了IaaS、PaaS和SaaS。原生就是土生土长的意思,我们在开始设计应用的时候就考虑到应用将来是运行云环境里面的,要充分利用云资源的优点,比如️云服务的弹性和分布式优势。
云原生是基于分布部署和统一运管的云端服务,以容器、微服务、DevOps等技术为基础建立的一套云技术产品体系。云原生指的是一个灵活的工程团队,遵循敏捷的研发原则,使用高度自动化的研发工具,开发专门基于并部署在云基础设施上的应用,以满足快速变化的客户需求。这些应用采用自动化的,可扩展的,和高可用的架构。这个工程团队通过高效的云计算现网的运维来提供这一应用服务,并且根据线上反馈对服务进行不断地改进。
2、云原生的组成
云原生 = 微服务 + DevOps + 持续交付 + 容器化。
微服务是一种软件开发技术,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。微服务体系结构有许多重要的好处。首先,它解决了业务复杂性的问题。它将原来庞大的单个应用程序分解为一组服务。尽管功能的总数保持不变,但应用程序已被分解为可管理的服务。单个服务的开发速度要快得多,而且更容易理解和维护。其次,这种架构允许每个服务由一个团队独立开发。开发人员可以自由选择任何适当的技术。第三,微服务架构模式允许各个服务独立部署。开发人员永远不需要协调对其服务的本地更改的部署。这些类型的更改可以在测试后立即部署。最后,微服务体系结构允许每个服务独立扩展。
DevOps的意思就是开发和运维不再是分开的两个团队,而是你中有我,我中有你的一个团队。我们现在开发和运维已经是一个团队了,但是运维方面的知识和经验还需要持续提高。
持续交付的意思就是在不影响用户使用服务的前提下频繁把新功能发布给用户使用,要做到这点非常非常难。我们现在两周一个版本,每次上线之后都会给不同的用户造成不同程度的影响。
容器化的好处在于运维的时候不需要再关心每个服务所使用的技术栈了,每个服务都被无差别地封装在容器里,可以被无差别地管理和维护,现在比较流行的工具是docker和k8s。
3、云原生与k8s
k8s是云原生的重要组成部分, k8s由Node、Pod、Service、Volume、Label等组成。
Master
- 集群控制节点,每个集群需要至少一个master节点负责集群的管控;
Node
- 工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker 负责容器的运行,运行真正的应用程序,在Node上Kubernetes管理的最小运行单元是Pod。
- Node上运行着Kubernetes的Kubelet、kube-proxy服务进程,这些服务进程负责Pod的创建、启动、监控、重启、销毁、以及实现软件模式的负载均衡。
Node包含的信息:
- Node地址:主机的IP地址,或Node ID。
- Node的运行状态:Pending、Running、Terminated三种状态。
- Node系统容量(Node Condition):描述Node可用的系统资源,包括CPU、内存、最大可调度Pod数量等。
- 其他:内核版本号、Kubernetes版本等。
Pod
- Pod是Kubernetes最基本的操作单元,包含一个或多个紧密相关的容器,一个Pod可以被一个容器化的环境看作应用层的“逻辑宿主机”;
- 一个Pod中的多个容器应用通常是紧密耦合的,Pod在Node上被创建、启动或者销毁;每个Pod里运行着一个特殊的被称之为Pause的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷,因此他们之间通信和数据交换更为高效,在设计时我们可以充分利用这一特性将一组密切相关的服务进程放入同一个Pod中。同一个Pod里的容器之间仅需通过localhost就能互相通信。
一个Pod中的应用容器共享同一组资源:
- PID命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID;
- 网络命名空间:Pod中的多个容器能够访问同一个IP和端口范围;
- IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信;
- UTS命名空间:Pod中的多个容器共享一个主机名;
- Volumes(共享存储卷):Pod中的各个容器可以访问在Pod级别定义的Volumes;Pod的生命周期通过Replication Controller来管理;通过模板进行定义,然后分配到一个Node上运行,在Pod所包含容器运行结束后,Pod结束。
Controller
- 控制器,通过它来实现对pod的管理,比如启动、停止、伸缩pod的数量。
Service
pod对外服务的统一入口,下面可以维护者同一类的多个pod。在Kubernetes的世界里,虽然每个Pod都会被分配一个单独的IP地址,但这个IP地址会随着Pod的销毁而消失,这就引出一个问题:
- 如果有一组Pod组成一个集群来提供服务,那么如何来访问它呢?Service!一个Service可以看作一组提供相同服务的Pod的对外访问接口,Service作用于哪些Pod是通过Label Selector来定义的。拥有一个指定的名字(比如my-mysql-server);
- 拥有一个虚拟IP(Cluster IP、Service IP或VIP)和端口号,销毁之前不会改变,只能内网访问;
- 能够提供某种远程服务能力;被映射到了提供这种服务能力的一组容器应用上;
- 如果Service要提供外网服务,需指定公共IP和NodePort,或外部负载均衡器;
- NodePort 系统会在Kubernetes集群中的每个Node上打开一个主机的真实端口,这样,能够访问Node的客户端就能通过这个端口访问到内部的Service了
Label
- 标签,用于对pod进行分类,同一类pod会拥有相同的标签。
- Label以key/value的形式附加到各种对象上,如Pod、Service、RC、Node等,以识别这些对象,管理关联关系等,如Service和Pod的关联关系。
NameSpace
- 命名空间,用来隔离pod的运行环境。
二、k8s集群搭建
集群架构图
1、系统环境准备
三台centos7虚拟机,主机名分别为master(192.168.2.8)、slave1(192.168.2.9)、 slave2(192.168.2.10),并安装好docker环境, docker安装成功后检测如下:
安装好docker后,进行如下设置
关闭 防火墙 、selinux、swap分区
systemctl stop firewalld && systemctl disable firewalld sed -i 's/enforcing/disabled/' /etc/selinux/config sed -ri 's/.*swap.*/#&/' /etc/fstab
将桥接IPv4 流量传递到iptables链
cat > /etc/sysctl.d/k8s.conf <<EOF net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF
生效操作: sysctl --system (sysctl -p /etc/sysctl.d/k8s.conf)
同步主机的时间
yum install ntpdate -y ntpdate -u time.windows.com
生成CA秘钥、Certificates证书
在master节点安装CFSSL工具用来建立TLS certificates
export CFSSL_URL="https://pkg.cfssl.org/R1.2" wget "${CFSSL_URL}/cfssl_linux-amd64" -O /usr/local/bin/cfssl wget "${CFSSL_URL}/cfssljson_linux-amd64" -O /usr/local/bin/cfssljson chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson
在/etc/etcd/ssl目录下创建ca-config.json、etcd-ca-csr.json秘钥配置用于生成CA的秘钥。etcd-csr.json秘钥配置用于生成Certificate证书
mkdir -p /etc/etcd/ssl && cd /etc/etcd/ssl #ca-config.json { "signing": { "default": { "expiry": "8760h" }, "profiles": { "kubernetes": { "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "expiry": "8760h" } } } } #etcd-ca-csr.json { "CN": "kubernetes", "key": { "algo": "rsa", "size": 2048 }, "names": [{ "C": "CN", "ST": "HeNan", "L": "ZhengZhou", "O": "k8s", "OU": "wmy" }] } #etcd-csr.json 其中hosts为集群的ip { "CN": "etcd", "key": { "algo": "rsa", "size": 2048 }, "hosts": [ "127.0.0.1", "192.168.2.8", "192.168.2.9", "192.168.2.10" ], "names": [ { "C": "CN", "L": "ZhengZhou", "O": "etcd", "OU": "etcd Security", "ST": "ZhengZhou" } ] }
生成CA秘钥文件
cfssl gencert -initca etcd-ca-csr.json | cfssljson -bare etcd-ca
生成 kube-apiserver certificate 证书
cfssl gencert -ca=etcd-ca.pem -ca-key=etcd-ca-key.pem -config=ca-config.json -profile=kubernetes etcd-csr.json | cfssljson -bare etcd
最终生产5个证书文件
将5个文件分发到salve1 、salve2相应的目录上
scp -r /etc/etcd/ssl root@slave1:/etc/etcd/ssl scp -r /etc/etcd/ssl root@slave2:/etc/etcd/ssl
2、k8s集群部署
添加阿里云的镜像源
cat > /etc/docker/daemon.json << EOF { "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"] } EOF 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 #exclude= kubeadm kubelet kubectl EOF
安装 kubeadm,kubelet 、kubectl
其中kubelet分布在集群中的每个节点,负责启动pod容器,kubeadm用于初始化k8s集群, kubectl用于增删查各种k8s的资源的工具类。
#cnetos安装 yum install -y kubelet-1.23.15 kubeadm-1.23.15 kubectl-1.23.15 systemctl enable kubelet --now
注:如果kubelet无法正常启动(journalctl -xeu kubelet 查看启启动日志),一般情况下检查一下/etc/docker/daemon.json是否存在以下配置:
"exec-opts": [ "native.cgroupdriver=systemd" ],
修改后重启docker: systemctl restart docker
部署Kubernetes Master
在 192.168.2.8(Master)执行为了提高安装成功率,安装之前先做一次重置,指定阿里 云镜像仓库地址
kubeadm reset #替换镜像地址 kubeadm config images list kubeadm config images list --image-repository registry.aliyuncs.com/google_containers #拉镜像 kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers
集群主机节点初始化操作
kubeadm init \ --apiserver-advertise-address=192.168.2.8 \ --image-repository registry.aliyuncs.com/google_containers \ --kubernetes-version v1.23.15 \ --service-cidr=10.96.0.0/12 \ --pod-network-cidr=10.244.0.0/16 \ --ignore-preflight-errors=all
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
主节点初始化成功后,下载安装 Pod 网络插件(cni-plugins-linux-amd64-v1.1.1.tgz)
mkdir -p /opt/cni/bin tar -C /opt/cni/bin -zxvf cni-plugins-linux-amd64-v1.1.1.tgz yum install kubernetes-cni -y
网络cni有多重方式,这里提供两种fannel 和calico
##fannel方式 wget https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml kubectl apply –f kube-fannel.yml ------------------------------------------------------------------------------------ ##calico方式 wget https://docs.projectcalico.org/manifests/calico.yaml 将calico.yaml中引用的镜像提前拉取 docker pull docker.io/calico/node:v3.26.1 docker pull docker.io/calico/kube-controllers:v3.26.1 docker pull docker.io/calico/cni:v3.26.1 修改calico.yaml中CALICO_IPV4POOL_CIDR的网段与集群初始化时候的保持一直 - name: CALICO_IPV4POOL_CIDR value: "10.244.0.0/16" kubectl apply –f calico.yaml
初始化工作节点
向集群添加新节点,执行在 kubeadm init 输出的 kubeadm join 命令(证书在master安装
后会 直接显示出来,直接拷贝过来)
kubeadm join 192.168.2.8:6443 --token 7s9vq1.4d5kp8yubatwjzgr --discovery-token-ca-cert-hash sha256:5b042272bbd8b8692581202ba7dba8e1721078facb40878485d40bde8b1d986e --ignore-preflight-errors=all
注:如果token过期可以使用以下方式创建查询
#查看token kubeadm token list #创建token kubeadm token create --print-join-command
查看k8s集群
kubectl get nodes
如果节点的状态为NotReady,查询日志进行排查:
journalctl -f -u kubelet.service kubectl describe node nodename
验证k8s集群环境
在 Kubernetes 集群中创建一个 pod,安装nignx镜像容器
kubectl create deployment nginx --image=nginx kubectl expose deployment nginx --port=80 --type=NodePort kubectl get pod,svc
注:可以通过下面的方式生成部署的yaml文件
kubectl create deployment nginx --image=nginx --dry-run -o yaml
查看nignx的端口
访问nignx的默认页面 http://192.168.2.8:31521
kubernetes-dashboard安装
命令行操作不是很方便,可以安装部署kubepi可视化操作
docker pull kubeoperator/kubepi-server docker run --privileged -itd --restart=unless-stopped --name kube_dashboard -v /home/docker-mount/kubepi/:/var/lib/kubepi/ -p 7110:80 kubeoperator/kubepi-server
创建访问账户、获取访问令牌
#创建sa账户 kubectl create sa kubepi-user --namespace kube-system #分配角色 kubectl create clusterrolebinding kubepi-user --clusterrole=cluster-admin --serviceaccount=kube-system:kubepi-user #查询访问令牌token kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep kubepi-user | awk '{print $1}') | grep token: | awk '{print $2}' #获取集群地址 cat ~/.kube/config | grep server: | awk '{print $2}'
访问dashboard管理页面(http://master:7110/ ),默认账密(admin/kubepi)
三、k8s常用命令
#开机自启 systemctl enable kubelet #禁用自启 systemctl disable kubelet #删除从节点 kubelet delete node slave1 #创建命名空间 kubectl create namespace ns-test #查看节点 kubectl get nodes kubectl get node -A #查看执行任务 kubectl get job -n ns-test #查询pods kubectl get pods -A kubectl get pods -n kube-ns-test -o wide #查询部署情况 kubectl describe ndoe nodeNamekueb kubectl describe -n ns-test svc <service名> kubectl describe -n ns-test deployment <deployment名> kubectl describe -n ns-test pod <pod名> #查询持久卷 kubectl get pv -A #查询持久卷声明 kubectl get -n ns-test pvc #查询存储类型 kubectl get storageclass -A #副本扩容 kubectl scale --replicas=3 dev #查看服务信息 kubectl get svc -A #查看服务日志 kubectl logs -f -n ns-test <pod名> #服务交互 kubectl exec -it -n ns-test <pod名> /bin/bash #删除pod deployment service kubectl delete -n ns-test pod <pod名> kubectl delete -n ns-test deployment <deployment名> kubectl delete -n ns-test svc <service名>
四、k8s集群卸载
- k8s 卸载
kubeadm reset -f yum remove -y kubelet kubeadm kubectl modprobe -r ipip lsmod
- 删除配置文件
rm -rf ~/.kube/ rm -rf /etc/kubernetes/ rm -rf /etc/systemd/system/kubelet.service.d rm -rf /etc/systemd/system/kubelet.service rm -rf /usr/bin/kube* rm -rf /etc/cni rm -rf /opt/cni rm -rf /var/lib/etcd rm -rf /var/etcd
- 更新镜像
yum clean all yum makecache
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。