什么是k8s
从官方文档中的介绍说k8s是一个开源的,用于管理云平台中多个主机上的容器化的应用,目标是让部署容器化的应用简单并且高效,k8s提供了应用部署,规划,更新,维护的一种机制。k8s很重要的一个特点就是能够自主管理容器来保证云平台中的容器按照用户的期望状态运行,一般用的容器化服务就是docker。简单说来,k8s就是一个管理容器的应用。
k8s的架构图
k8s的组件介绍
从整体来看,k8s分为Master节点和Node节点,其中Master由Apiserver、scheduler、controller-manager、etcd组件组成。
Apiserver:所有服务的统一访问入口。
controller-manager:负责管理集群中的各种资源,保证资源处于预期的状态。
Scheduler:资源调度器,负责介绍任务,选择合适的节点分配任务。即决定将pod放在哪个node上运行,scheduler在调度的时候会对整个集群的结构进行分析,当前各个节点的负载,以及应用对高可用、性能等方面的需求。
Etcd:键值对数据库,存储k8s集群所有重要信息(持久化),etcd还提供监听机制,当数据发生变化的时候,etcd会快速通知apiserver,并由其通过watch api向客户端输出。由此可见,etcd是一个k8s集群的核心组件,但是etcd并不隶属于k8s集群,它是一个独立的服务组件,在生产环境中etcd应该以集群的方式运行,以保证服务的可用性。
在node节点中,有kubelet、kube-proxy、docker等组件组成。
kubelet:直接跟容器引擎进行交互实现容器的生命周期管理,kubelet就相当于是每个node的执行员,调度器确定在某个node上运行pod后,会将pod的具体配置信息发送给节点的kubelet,之后kubelet会根据这些信息创建和运行相应的容器,并向master报告运行的状态。
kube-proxy:这是一个转发功能,外界通过service访问pod,service接收到请求之后需要kube-proxy转发到pod;每个node都会运行kube-proxy服务,负责将访问service的TCP/UDP数据流转发到后端的容器,如果有多个副本,kube-proxy会实现负载均衡,有两种实现方式:LVS或者Iptables。
除了这些组件还有一些比较重要的附件组件:
CoreDNS:可以为集群中的SVC创建一个域名IP对应关系的解析。
Dashboard:为k8s集群提供一个 B/S 结构的访问体系。
Ingress Controller:官方只能实现四层代理,INGRESS可以实现七层代理。
Fedeation:提供一个可以跨集群中心多k8s统一管理功能。
Prometheus:为k8s集群提供监控功能。
Pod概念
Pod可以分为两种类型:自主式Pod和static Pod。一个pod只有一个通讯寻地址,pod中的容器共用一个pause的网络簇。
Pod管理器
Pod管理器有RS、RC、Deployment、StatefulSet等。
ReplicationController是用来确保容器应用的副本数始终保持在用户定义的副本数,即有容器异常退出,会自动创建新的Pod来代替;而如果异常多出来的容器 也会自动回收。在新版本的k8s中建议使用ReplicaSet来代替ReplicationController。
ReplicaSet跟ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector。
虽然ReplicaSet可以独立使用,但一般还是建议使用Deployment来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题(如ReplicaSet不支持rolling-update但Deployment支持)。
StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),应用场景包括:
● 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于pvc来实现。
● 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现。
● 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候需要根据定义的顺序依次进行(即从0到N-1,在下一个Pod运行之前所有值钱的Pod必须是Running和Ready状态),基于init containers来实现
● 有序收缩,有序删除(即从N-1到0)
DaemonSet确保全部(或者一些)Node上运行一个Pod副本,当有Node加入集群时,也会为他们新增一个Pod。当有Node从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod。
Job负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。Cron Job管理基于时间的Job,即:
● 在给定时间点只运行一次
● 周期性的再给定时间点运行
自主式Pod
自主式Pod总是在前台运行,同时接受k8s的管理与调度,在集群中的Pod因某种原因停止,k8s会根据其副本数量,重新生成对应的Pod。
static Pod
static Pod由kubelet进行创建和管理,一般存在于特定的node上,不通过apiserver管理,并且与Pod管理器(RC,deployment…)无关联,而起kubelet无法实现其健康检查,只能人工手动进行;static Pod的创建方式有两种:文件方式与http方式。
网络通讯模式
Kubernetes的网络模型假定了所有的Pod都在一个可以直接连通的扁平的网络空间中,在GCE里面是现成的网络模型,kubernetes假定这个网络已经存在。而在私有云中搭建kubernetes集群,就不能假定这个网络已经存咋,需要自己实现这个网络假设,将不同节点上的docker容器之间的互相访问先打通,然后运行kubernetes。
同一个Pod内的多个容器之间:lo
各Pod之间的通讯:Overlay Network
Pod与Service之间的通讯:各节点的Iptables规则。
Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址,而且他还能在这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动的传递到目标容器内。
ETCD之Flannel:存储管理Flannel 可分配的IP地址段资源;监控ETCD中每个Pod的实际地址,并在内存中建立维护Pod节点路由表。
安装k8s集群
在这里使用三台主机,一台master,两台node,设置主机名并相互解析,做好主机的初始化设置。
安装依赖包
yum install -y conntrack ntpdate ntp ipvsadm ipset jq ptables curl sysstat libseccomp wget net-tools git
设置防火墙为Iptables并清空规则
systemctl stop firewalld && systemctl disable firewalld
yum -y install iptables-services && systemctl start iptables && systemctl enable iptables && iptables -F && service iptables save
关闭selinux以及swap
swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
调整内核参数,对k8s
cat > kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_in_oom=0
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720
EOF
cp kubernetes.conf /etc/sysctl.d/kubernetes.conf
sysctl -p /etc/sysctl.d/kubernetes.conf
调整系统时区
调整系统时区为中国上海,关闭系统不需要服务
systemctl stop postfix && systemctl disable postfix
设置rsyslogd和systemd journald
mkdir /var/log/journal #持久化保存日志的目录
mkdir /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF
[Journal]
#持久化保存到磁盘
Storage=persistent
#压缩历史日志
Compress=yes
SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=1000
#最大占用空间
SystemMaxUse=10G
#单日志文件最大
SystemMaxFileSize=200M
#日志保存时间为2周
MaxRetentionSec=2week
#不将日志转发到syslog
ForwardToSyslog=no
EOF
systemctl restart systemd-journald
升级内核为4.44
centos 7.x系统自带3.10.x内核存在一些bugs,导致运行docker、k8s不稳定
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install -y kernel-lt
grub2-set-default "Centos Linux (4.4.182-1.e17.elrepo.x86_64) 7 (Core)"
kube-proxy开启ipvs的前置条件
modprobe br_netfilter
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod |grep -e ip_vs -e nf_conntrack_ipv4
安装docker软件
yum install -y yum-utils device-mapper-persistent-data lvm2 #安装依赖
配置docker的yum源,选择阿里云的docker-ce
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
安装docker-ce
yum install -y docker-ce && systemctl start docker && systemctl enable docker
配置daemon
cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
}
}
EOF
mkdir -p /etc/systemd/system/docker.service.d
systemctl daemon-reload && systemctl restart docker && systemctl enable docker
安装kubeadm v1.18.6
cat > /etc/yum.repos.d/kubenetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
enabled=1
EOF
yum install -y kubeadm-1.18.6 kubectl-1.18.6 kubelet-1.18.6
systemctl enable kubelet
拉取镜像
cat>pull_images.sh<<'EOF'
#!/bin/bash
KUBE_VERSION=v1.18.6
FLANNEL_VERSION=v0.12.0-amd64
KUBE_PAUSE_VERSION=3.2
ETCD_VERSION=3.4.3-0
DNS_VERSION=1.6.7
prefix=registry.cn-chengdu.aliyuncs.com/gcrs
images=(
kube-proxy:${KUBE_VERSION}
kube-scheduler:${KUBE_VERSION}
kube-controller-manager:${KUBE_VERSION}
kube-apiserver:${KUBE_VERSION}
pause:${KUBE_PAUSE_VERSION}
etcd:${ETCD_VERSION}
coredns:${DNS_VERSION}
)
for image in ${images[@]}
do
docker pull ${prefix}/${image}
docker tag ${prefix}/${image} k8s.gcr.io/${image}
docker rmi ${prefix}/${image}
done
#prefix仓库里面没有flannel,单独拉取
docker pull $prefix/flannel:${FLANNEL_VERSION}
EOF
sh pull_images.sh
进行master节点的初始化
之后即可在master节点上开始进行初始化
kubeadm init --kubernetes-version=v1.18.6 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --ignore-preflight-errors=Swap
初始化完成之后即会有提示,将Your Kubernetes master has initialized successfully!一句话下面的内容保存到一个文件中。
按照上面的提示进行操作。
先不用添加节点,
检查一下集群状态是否正常
kubectl get componentstatus
出现错误解决方法
The connection to the server localhost:8080 was refused - did you specify the right host or port?
解决方法
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
出现错误解决方法
解决方法
vim /etc/kubernetes/manifests/kube-scheduler.yaml
- --port=0 #将这行去掉
vim /etc/kubernetes/manifests/kube-controller-manager.yaml
- --port=0 #将这行去掉
systemctl restart kubelet
之后在master上添加网络组件
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
然后检查状态
kubectl get pods -n kube-system -l app=flannel
之后检查master节点是否准备完成
~]# kubectl get nodes
然后在node节点上执行提示的添加节点的命令,执行成功之后在master节点上查看是否准备就绪
kubectl get nodes
如未就绪可能是防火墙问题。
为node的角色打标签
kubectl label node node01 node-role.kubernetes.io/node=node
安装dashboard
下载yml文件
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
修改配置
[root@k8s-master dashboard]# vim recommended.yaml
...
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: NodePort # 新增
ports:
- port: 443
targetPort: 8443
nodePort: 30443 # 新增
selector:
k8s-app: kubernetes-dashboard
安装dashboard
kubectl create -f recommended.yaml
确认状态
kubectl get pod,svc -n kubernetes-dashboard
创建管理员用户yaml
vim adminuser.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
创建管理员权限
kubectl create -f adminuser.yaml
获取token,用于登录dashboard
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
k8s的dashboard报告错误
Error from server (Forbidden): Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=proxy)
解决方法:绑定一个cluster-admin的权限
kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
部署Prometheus+Grafana
git clone https://gitee.com/liugpwwwroot/k8s-prometheus-grafana.git
kubectl create -f k8s-prometheus-grafana/node-exporter.yaml #部署Node-exporter组件
#部署prometheus组件
kubectl create -f k8s-prometheus-grafana/prometheus/rbac-setup.yaml
kubectl create -f k8s-prometheus-grafana/prometheus/configmap.yaml
kubectl create -f k8s-prometheus-grafana/prometheus/prometheus.deploy.yml
kubectl create -f k8s-prometheus-grafana/prometheus/prometheus.svc.yml
#部署grafana组件
kubectl create -f k8s-prometheus-grafana/grafana/grafana-deploy.yaml
kubectl create -f k8s-prometheus-grafana/grafana/grafana-svc.yaml
kubectl create -f k8s-prometheus-grafana/grafana/grafana-ing.yaml
kubectl get svc -n kube-system #查看相应服务
之后访问相应服务
进入gafana后添加数据源,直接访问的话填访问prometheus的ip加端口。
部署实例
vim nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx-app
replicas: 2
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
创建svc
kubectl expose deployment nginx --port=80 --type=LoadBalancer
查看暴露端口
kubectl get service
后访问相应服务
进入gafana后添加数据源,直接访问的话填访问prometheus的ip加端口。
部署实例
vim nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx-app
replicas: 2
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
创建pod
kubectl create -f nginx.yaml
创建svc
kubectl expose deployment nginx --port=80 --type=LoadBalancer
查看暴露端口
kubectl get service
浏览器访问IP:Port