上篇文章《架构的进化》讲到了云原生k8s,这里会搭建一个K8S集群以增强认知。

1、购买机器

在阿里云购买三台ECS,信息如下(直接购买不要纠结,否则后面各种组件根本安装不上)

ip

角色

配置

OS

106.15.43.143

master

1 vCPU 4 GiB

CentOS Stream 9 64位

139.224.137.71

node1

4 vCPU 4 GiB

CentOS Stream 9 64位

47.100.242.177

node2

1 vCPU 2 GiB

CentOS Stream 9 64位

2、部署K8S集群

master上执行。看清楚每个命令,不要一把梭

yum update
yum -y upgrade systemd
 
# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
 
# 关闭selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config
 
# 关闭swap
sed -ri 's/.*swap.*/#&/' /etc/fstab
 
# 开启iptable转发。ecs每次重启都要执行一遍
modprobe ip_tables
modprobe iptable_filter
 
# 设置主机名
hostnamectl set-hostname master
 
# 添加hosts(这里是ecs内网ip,请用你自己的)
cat >> /etc/hosts << EOF
172.19.226.68 master
172.19.226.67 node1
172.19.226.69 node2
EOF
 
# 将桥接的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
 
# 安装 Docker
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum -y install docker-ce
systemctl enable docker && systemctl start docker
 
# 为docker配置镜像下载加速器(镜像地址请用你自己的,阿里云官网搜索【容器镜像服务 ACR】)
vim /etc/docker/daemon.json
 
{
  "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}
 
systemctl restart docker
docker info
 
# 安装 kubeadm、kubelet、kubectl
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
 
yum install -y kubelet-1.23.0 kubeadm-1.23.0 kubectl-1.23.0
systemctl enable kubelet
 
# 部署k8s-master。第一次不要加ignore-preflight-errors参数,看会报什么错。有些错可以忽略,有些需要处理
kubeadm init \
  --apiserver-advertise-address=172.19.226.68 \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.23.0 \
  --service-cidr=10.96.0.0/12 \
  --pod-network-cidr=10.244.0.0/16
 
# 如果初始化成功,会输出一些命令+信息,直接拷贝执行即可
# 如果不成功,去第三部分查看原因
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
 
# 复制其中的join命令,稍后去node上执行
 
# 默认token有效期为24小时,当过期之后,该token就不可用了。这时就需要重新创建token,可以直接使用命令快捷生成
# kubeadm token create --print-join-command

node上执行。看清楚每个命令,不要一把梭

yum update
yum -y upgrade systemd
 
# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
 
# 关闭selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config
 
# 关闭swap
sed -ri 's/.*swap.*/#&/' /etc/fstab
 
# ecs每次重启后都要执行一遍
modprobe ip_tables
modprobe iptable_filter
 
# 设置主机名。注意node2自己修改命令
hostnamectl set-hostname node1
 
# 设置hosts。注意node2自己修改命令
vim /etc/hosts
 
127.0.0.1    node1
 
# 将桥接的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
 
# 安装 Docker、kubeadm、kubelet
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum -y install docker-ce
systemctl enable docker && systemctl start docker
 
# 配置镜像下载加速器(加速器请用你自己的)
vim /etc/docker/daemon.json
 
{
  "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"]
}
 
systemctl restart docker
docker info
 
# 安装 kubeadm、kubelet、kubectl
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
 
yum install -y kubelet-1.23.0 kubeadm-1.23.0 kubectl-1.23.0
systemctl enable kubelet
 
# 加入集群。请使用自己在master上生成的命令
# kubeadm join 10.151.30.57:6443 --token 8xomlq.0cdf2pbvjs2gjho3 --discovery-token-ca-cert-hash sha256:92802317cb393682c1d1356c15e8b4ec8af2b8e5143ffd04d8be4eafb5fae368
# 可能会报错,如果可以忽略,则添加--ignore-preflight-errors=all参数后重试

3、第二步可能的报错

(1)

一键部署NFS 一键部署k8s集群_一键部署NFS

解决办法

rm -rf /etc/containerd/config.toml
systemctl restart containerd

(2)

一键部署NFS 一键部署k8s集群_容器_02

/proc/sys/net/ipv4/ip_forward这个文件表示是否打开IP转发。0代表禁止、1代表转发

# 使用下列命令,查看文件的内容
less /proc/sys/net/ipv4/ip_forward

一键部署NFS 一键部署k8s集群_容器_03

# 使用下列命令,更改文件的内容
echo "1" > /proc/sys/net/ipv4/ip_forward

# 重启网络服务
service network restart

(3)

一键部署NFS 一键部署k8s集群_容器_04

Failed to update Node Allocatable Limits ["kubepods"]: openat2 /sys/fs/cgroup/kubepods.slice/cpu.weight: no such file or directory

图片与这行报错似乎是同一个问题导致的,尚未找到解决办法,可能与容器驱动有关。可以添加参数--ignore-preflight-errors=all来忽略掉

4、安装网络插件

经过上面操作后查看nodes状态,都是NotReady。是因为还需要安装网络插件

kubectl get nodes

因为是实验性质的集群,安装一个简单插件

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

再次查看集群状态

# 需要等一会各个pod才能进入running状态
kubectl get pod -n kube-system
kubectl get nodes

一键部署NFS 一键部署k8s集群_软件工程_05

pod可能出现各种状态:pending、backoff等,需要具体排查。常用命令如下

# 查看pod日志
kubectl logs XXXpodName -n kube-system
# 查看信息,关注最后的events
kubectl describe pod XXXpodName -n kube-system
#
journalctl -l -u kube-apiserver
journalctl -l -u kube-controller-manager
journalctl -l -u kube-scheduler
journalctl -l -u kubelet
journalctl -l -u kube-proxy

5、部署Dashboard

wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml

 默认Dashboard只能集群内部访问,修改Service为NodePort类型,暴露到外部

vi recommended.yaml
...
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30001
  selector:
    k8s-app: kubernetes-dashboard
  type: NodePort
...

这是修改过的recommended.yaml文件,你可以直接使用。下面来安装它

# 安装
kubectl apply -f recommended.yaml
# 查看状态
kubectl get pods -n kubernetes-dashboard
 
# 创建用户
kubectl create serviceaccount dashboard-admin -n kube-system
# 用户授权
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
# 获取用户Token
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')

观察dashboard安装在哪台节点上,访问https://139.224.137.71:30001/#/login,输入生成的token即可

一键部署NFS 一键部署k8s集群_kubernetes_06

一键部署NFS 一键部署k8s集群_docker_07

小显身手:部署应用

下面根据nginx镜像生成yaml,然后在我们的k8s上安装

kubectl create deployment web --image=nginx:1.14 --dry-run=server -o yaml > web.yaml

# create deployment web 创建一个名为 web 的 deployment 资源

# --dry-run 表示检查语法,但不实际执行。从一个已有的镜像反向生成yaml,目的是让机器帮我们生成yaml

# -o yaml 表示以 yaml 格式输出

# > web.yaml 表示输出重定向到 web.yaml

kubectl apply -f web.yaml

使用dashboard可以看到这个容器(默认在default空间下),点击这个pod查看详细信息,能够获得ip。curl 10.24.1.11,如果有nginx的标准返回说明应用已经部署完毕。

一键部署NFS 一键部署k8s集群_kubernetes_08

一键部署NFS 一键部署k8s集群_kubernetes_09

 k8s扩容,只需要修改之前的web.yaml文件,将replicas的值改为10,然后再更新配置

kubectl replace -f web.yaml

也可以直接使用scale命令,一键指定副本数

kubectl scale deploy web --replicas=2

删除部署应用,只删除pod是没用的,因为有deployment会自动维护其pod为指定数量,需要删除deployment

# 查看你的pod在哪个空间下(部署的应用默认是在default空间)
kubectl get pods --all-namespaces
 
# 查看该空间有哪些deployment
kubectl get deployment -n default
 
# 删除deployment
kubectl delete deployment xxx -n default

部署自己的应用

我们自己写代码如何部署到k8s呢?本地golang新建一个项目,有以下文件

一键部署NFS 一键部署k8s集群_kubernetes_10

  • A.go:是我们的项目代码,业务逻辑
  • demo:是编译后的可执行文件(如果本地是windows系统,可以交叉编译为linux下的可执行文件;也可以将源文件拷贝到linux上编译)
  • Dockerfile:D一定要大写,这是构建docker镜像的文件
  • k8s-test-com.yaml:名字随便取,是k8s用来部署pod的描述文件

将除了A.go的所有文件拷贝到master节点

一键部署NFS 一键部署k8s集群_软件工程_11

 利用docker打包镜像

# 先去docker hub官网注册一个账号,然后本地登录。不要做其它操作
docker login
 
# 打包镜像
docker build -t youngaoo01/demo:01 .
 
# 如果你在dockerHub上手动创建了一个仓库,那么打完镜像后,需要再打tag
 
# 查看刚打的镜像
docker iamges
 
# 推到dockerHub上
docker push youngaoo01/demo:01
 
# 删除本地镜像。毕竟这是在master节点上,又不需要运行负载pod,要这个镜像也没用
docker rmi youngaoo01/demo:01
 
# 安装pod
kubectl apply -f k8s-test-com.yaml

运行完毕后,去dashboard上看看吧,并请求一下试试

(docker仓库用起来感觉慢慢的,可以用阿里云的仓库)

HPA V2

部署采集工具metrics

我对metrics的deployment文件做了一些修改,以便更加容易安装:

两个修改点:1替换镜像k8s.gcr.io/metrics-server/metrics-server:v0.6.2为registry.aliyuncs.com/google_containers/metrics-server:v0.6.2,2增加- --kubelet-insecure-tls

这是我修改好的components.yaml,你可以直接使用

kubectl apply -f components.yaml
kubectl get pods --all-namespaces

部署完毕后,可以查看节点负载,也可以基于cpu来扩缩容

# 节点负载
kubectl top node
 
# cpu大于40则扩容。testya是我们上面部署自己代码时起的pod名字,在k8s-test-com.yaml中
kubectl autoscale deployment testya --cpu-percent=40 --min=1 --max=3
 
# 哪些pod具有hpa
kubectl get hpa
 
# 删除hpa
# kubectl delete hpa XXname

一键部署NFS 一键部署k8s集群_docker_12

看上图,显示unknow。需要对k8s-test-com.yaml修改,增加以下配置

一键部署NFS 一键部署k8s集群_docker_13

 m是cpu的单位。1000m代表它要使用一个cpu,那么500m就是0.5个cpu。修改完毕,然后删除deployment重新appply。

如果你有如下报错,要么你的requests.cpu配置的过大,要么你购买的cpu只有一核(请去为ecs升配)

0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 Insufficient cpu.
(0个节点可用:1个节点有污点(主节点不能运行负载),其它不满足2个cpu)

压测观察缩扩容

# 安装busybox
kubectl run -i --tty load-generator --image=busybox /bin/sh
 
# 输入以下脚本,单线程死循环请求(请使用你自己部署应用的ip)
while true; do wget -q -O- http://10.244.2.39:8080; done
 
# 如果退出了busybox pod也没关系,再次进入
# kubectl exec -it pod名称 /bin/sh -n default
# cd /bin
# ./sh
# 输入脚本

最终我们的pod扩容到2个实例,停止压测后,又缩回一个

疑问:我们压测时是直接请求pod的ip,而扩容后的新pod ip是新的,如何让请求能均匀地分散在两个pod上?

这就需要修改k8s-test-com.yaml文件增加一个service,类似于Nginx负载均衡。再次压测,请求这个service的ip+端口即可

一键部署NFS 一键部署k8s集群_一键部署NFS_14

 service不仅有集群ip+port,也会在节点机器上开一个端口,可以在外部使用ecs公网ip访问

一键部署NFS 一键部署k8s集群_kubernetes_15

后续章节:见该专栏的下篇文章

serverless架构介绍、k8s集群安装istio、knative