节点规划
部署k8s集群的节点按照用途可以划分为如下2类角色:
- master:集群的master节点,集群的初始化节点,基础配置不低于2C4G
- slave:集群的slave节点,可以多台,基础配置不低于2C4G
本例为了演示slave节点的添加,会部署一台master+2台slave,节点规划如下:
主机名 | 节点ip | 角色 | 部署组件 |
---|---|---|---|
k8s-master | xxx.xxx.xxx.xx | master | etcd, kube-apiserver, kube-controller-manager, kubectl, kubeadm, kubelet, kube-proxy, flannel |
k8s-slave1 | xxx.xxx.xxx.xx | slave | kubectl, kubelet, kube-proxy, flannel |
k8s-slave2 | xxx.xxx.xxx.xx | slave | kubectl, kubelet, kube-proxy, flannel |
组件版本
组件 | 版本 | 说明 |
---|---|---|
CentOS | 7.8.2003 | |
Kernel | Linux 3.10.0-1127.10.1.el7.x86_64 | |
etcd | 3.4.13-0 | 使用Pod方式部署,默认数据挂载到本地路径 |
coredns | 1.7.0 | |
kubeadm | v1.21.5 | |
kubectl | v1.21.5 | |
kubelet | v1.21.5 | |
kube-proxy | v1.21.5 | |
flannel | v0.19.2 |
设置hosts解析
操作节点:所有节点(k8s-master,k8s-slave
)均需执行
- 修改hostname hostname必须只能包含小写字母、数字、","、"-",且开头结尾必须是小写字母或数字
# 在master节点
$ hostnamectl set-hostname k8s-master #设置master节点的hostname
# 在slave-1节点
$ hostnamectl set-hostname k8s-slave1 #设置slave1节点的hostname
# 在slave-2节点
$ hostnamectl set-hostname k8s-slave2 #设置slave2节点的hostname
- 添加hosts解析
$ cat >>/etc/hosts<<EOF
xxx.xxx.xxx.xxx k8s-master
xxx.xxx.xxx.xxx k8s-slave1
xxx.xxx.xxx.xxx k8s-slave2
EOF
调整系统配置
操作节点: 所有的master和slave节点(k8s-master,k8s-slave
)需要执行
本章下述操作均以k8s-master为例,其他节点均是相同的操作(ip和hostname的值换成对应机器的真实值)
- 设置安全组开放端口
如果节点间无安全组限制(内网机器间可以任意访问),可以忽略,否则,至少保证如下端口可通: k8s-master节点:TCP:6443,2379,2380,60080,60081UDP协议端口全部打开 k8s-slave节点:UDP协议端口全部打开
- 设置iptables
iptables -P FORWARD ACCEPT
- 关闭swap
swapoff -a
# 防止开机自动挂载 swap 分区
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
- 关闭selinux和防火墙
sed -ri 's#(SELINUX=).*#\1disabled#' /etc/selinux/config
setenforce 0
systemctl disable firewalld && systemctl stop firewalld
- 修改内核参数
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
vm.max_map_count=262144
EOF
modprobe br_netfilter
sysctl -p /etc/sysctl.d/k8s.conf
- 设置yum源
$ curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
$ curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
$ cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
$ yum clean all && yum makecache
安装docker
操作节点: 所有节点
## 查看所有的可用版本
$ yum list docker-ce --showduplicates | sort -r
##安装旧版本 yum install docker-ce-cli-18.09.9-3.el7 docker-ce-18.09.9-3.el7
## 安装源里最新版本
$ yum install docker-ce-20.10.18 -y
## 配置docker加速和非安全的镜像仓库,需要根据个人的实际环境修改
$ mkdir -p /etc/docker
vi /etc/docker/daemon.json
{
"insecure-registries": [
"xxx.xxx.xxx.xxxx:5000" #公网ip地址
],
"registry-mirrors" : [
"https://8xpk5wnt.mirror.aliyuncs.com"
]
}
## 启动docker
$ systemctl enable docker && systemctl start docker
安装 kubeadm, kubelet 和 kubectl
操作节点: 所有的master和slave节点(k8s-master,k8s-slave
) 需要执行
$ yum install -y kubelet-1.24.4 kubeadm-1.24.4 kubectl-1.24.4 --disableexcludes=kubernetes
## 查看kubeadm 版本
$ kubeadm version
## 设置kubelet开机启动
$ systemctl enable kubelet
配置containerd
操作节点:所有的master和slave节点(k8s-master,k8s-slave
) 需要执行
-
将
sandbox_image
镜像源设置为阿里云google_containers
镜像源:# 导出默认配置,config.toml这个文件默认是不存在的 containerd config default > /etc/containerd/config.toml grep sandbox_image /etc/containerd/config.toml sed -i "s#k8s.gcr.io/pause#registry.aliyuncs.com/google_containers/pause#g" /etc/containerd/config.toml sed -i "s#registry.k8s.io/pause#registry.aliyuncs.com/google_containers/pause#g" /etc/containerd/config.toml
-
配置containerd cgroup 驱动程序systemd:
sed -i 's#SystemdCgroup = false#SystemdCgroup = true#g' /etc/containerd/config.toml
-
配置
docker hub
镜像加速:# 修改配置文件/etc/containerd/config.toml, 145行添加config_path ... 144 [plugins."io.containerd.grpc.v1.cri".registry] 145 config_path = "/etc/containerd/certs.d" 146 147 [plugins."io.containerd.grpc.v1.cri".registry.auths] 148 149 [plugins."io.containerd.grpc.v1.cri".registry.configs] 150 151 [plugins."io.containerd.grpc.v1.cri".registry.headers] 152 153 [plugins."io.containerd.grpc.v1.cri".registry.mirrors] ... # 创建对应的目录 mkdir -p /etc/containerd/certs.d/docker.io # 配置加速 cat >/etc/containerd/certs.d/docker.io/hosts.toml <<EOF server = "https://docker.io" [host."https://8xpk5wnt.mirror.aliyuncs.com"] capabilities = ["pull","resolve"] [host."https://docker.mirrors.ustc.edu.cn"] capabilities = ["pull","resolve"] [host."https://registry-1.docker.io"] capabilities = ["pull","resolve","push"] EOF
-
配置非安全的私有镜像仓库:
# 此处目录必须和个人环境中实际的仓库地址保持一致 mkdir -p /etc/containerd/certs.d/172.21.65.226:5000 cat >/etc/containerd/certs.d/172.21.65.226:5000/hosts.toml <<EOF server = "http://172.21.65.226:5000" [host."http://172.21.65.226:5000"] capabilities = ["pull", "resolve", "push"] skip_verify = true EOF
-
应用所有更改后,重新启动containerd:
systemctl restart containerd
初始化配置文件
操作节点: 只在master节点(k8s-master
)执行
$ kubeadm config print init-defaults > kubeadm.yaml
$ cat kubeadm.yaml
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: xxx.xxx.xxx.xxx # 此处替换为k8s-master的公网ip地址
bindPort: 6443
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
imagePullPolicy: IfNotPresent
name: k8s-master # 此处替换为k8s-master的hostname
taints: null
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers # 替换为国内镜像源
kind: ClusterConfiguration
kubernetesVersion: 1.24.4 # 替换为1.24.4
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16 # 添加此行,用来分配k8s节点的pod ip
serviceSubnet: 10.96.0.0/12
scheduler: {}
对于上面的资源清单的文档比较杂,要想完整了解上面的资源对象对应的属性,可以查看对应的 godoc 文档,地址: https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3。
提前下载镜像
操作节点:只在master节点(k8s-master
)执行
# 查看需要使用的镜像列表,若无问题,将得到如下列表
$ kubeadm config images list --config kubeadm.yaml
registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.4
registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.4
registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.4
registry.aliyuncs.com/google_containers/kube-proxy:v1.24.4
registry.aliyuncs.com/google_containers/pause:3.7
registry.aliyuncs.com/google_containers/etcd:3.5.3-0
registry.aliyuncs.com/google_containers/coredns:v1.8.6
# 提前下载镜像到本地
$ kubeadm config images pull --config kubeadm.yaml
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.4
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.4
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.4
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-proxy:v1.24.4
[config/images] Pulled registry.aliyuncs.com/google_containers/pause:3.7
[config/images] Pulled registry.aliyuncs.com/google_containers/etcd:3.5.3-0
[config/images] Pulled registry.aliyuncs.com/google_containers/coredns:v1.8.6
初始化master节点
操作节点:只在master节点(k8s-master
)执行,注意只在master节点执行!
$ kubeadm init --config kubeadm.yaml
第一次执行报错
查询资料后问题发现解决阿里云ECS下kubeadm部署k8s无法指定公网IP(作废) - LifeOfCoding - 博客园 (cnblogs.com)
解决问题
- 首先将生成的/etc/kubernetes/manifests/etcd.yaml文件进行修改
[root@k8s-master /etc/kubernetes/manifests]# vim etcd.yaml - --listen-client-urls=https://0.0.0.0:2379 - --listen-peer-urls=https://0.0.0.0:2380
进行保存。
-
清除配置
[root@k8s-master ~/k8s]# kubeadm reset
-
重新初始化
[root@k8s-master ~/k8s]# kubeadm init --config kubeadm.yaml --ignore-preflight-errors=FileAvailable--etc-kubernetes-manifests-etcd.yaml --v=7
此参数将指示
kubeadm
忽略因为 etcd 配置文件已存在而引发的前置检查错误。这将允许初始化过程继续进行而不会覆盖现有的etcd.yaml
文件。然而,请注意,忽略前置检查错误并继续进行可能涉及一定的风险。在忽略错误前,确保您完全理解为何存在该文件以及它的内容是否正确配置。如果该文件为由于以前未完成的初始化过程而遗留下来的,那么它可能不包含正确的配置,继续使用可能会导致集群初始化不正确或运行不稳定。
因此,在忽略这种错误之前,应当进行以下检查确保了解该文件的目的和内容。检查集群的当前状态,确认是否真的可以继续使用现有的
etcd
配置。特别是在生产环境中操作时,保持谨慎是非常重要的,因为对集群如果您已经存在/etc/kubernetes/manifests/etcd.yaml
文件,并且不希望在运行kubeadm init
时该文件被替换或改动,那么使用--ignore-preflight-errors
参数来忽略这个具体的错误是可行的。这个参数将会告诉kubeadm init
忽略检查到该文件已存在的这一错误,并继续执行初始化流程。确保有足够的备份,以防忽略这个错误后导致未预见的问题。如果不确定文件的准确性,或者是第一次初始化集群,建议备份然后移除该文件,让kubeadm init
生成新的配置。如果您需要忽略多个错误,可以使用逗号分隔各个错误名称,例如:kubeadm init --ignore-preflight-errors=FileAvailable--etc-kubernetes-manifests-etcd.yaml,SomeOtherError -
执行成功
接下来按照上述提示信息操作,配置kubectl客户端的认证,并将master节点的admin.conf拷贝至所有salve节点
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
⚠️注意:此时使用 kubectl get nodes查看节点应该处于notReady状态,因为还未配置网络插件
若执行初始化过程中出错,根据错误信息调整后,执行kubeadm reset后再次执行init操作即可
添加slave节点到集群中
操作节点:所有的slave节点(k8s-slave
)需要执行 在每台slave节点,执行如下命令,该命令是在kubeadm init成功后提示信息中打印出来的,需要替换成实际init后打印出的命令。
kubeadm join xxx.xxxx.xxx.xxxx:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1c4305f032f4bf534f628c32f5039084f4b103c922ff71b12a5f0f98d1ca9a4f
如果忘记添加命令,可以通过如下命令生成:
$ kubeadm token create --print-join-command
操作节点:只在master节点(k8s-master
)执行,CNI
-
下载flannel的yaml文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
-
修改配置,指定网卡名称,大概在文件的172行,添加一行配置:
$ vi kube-flannel.yml ... 150 containers: 151 - name: kube-flannel 152 #image: flannelcni/flannel:v0.19.2 for ppc64le and mips64le (dockerhub limitations may apply) 153 image: docker.io/rancher/mirrored-flannelcni-flannel:v0.19.2 154 command: 155 - /opt/bin/flanneld 156 args: 157 - --ip-masq 158 - --kube-subnet-mgr 159 - --iface=eth0 # 如果机器存在多网卡的话,指定内网网卡的名称,默认不指定的话会找第一块网卡 160 resources: 161 requests: 162 cpu: "100m" 163 memory: "50Mi" ...
-
确认pod网段
vi kube-flannel.yml 98 net-conf.json: | 99 { 100 "Network": "10.244.0.0/16", 101 "Backend": { 102 "Type": "vxlan" 103 } 104 } # 确认84行的网段和前面kubeadm.yaml中初始化使用的配置中的podSubnet保持一致!
-
执行安装flannel网络插件
# 执行flannel安装 kubectl apply -f kube-flannel.yml kubectl -n kube-flannel get po -owide
- node节点查询
- flannel网络查询
设置master节点是否可调度(可选)
操作节点:k8s-master
默认部署成功后,master节点无法调度业务pod,如需设置master节点也可以参与pod的调度,需执行:
kubectl taint node k8s-master node-role.kubernetes.io/master:NoSchedule-
kubectl taint node k8s-master node-role.kubernetes.io/control-plane:NoSchedule-
课程后期会部署系统组件到master节点,因此,此处建议设置k8s-master节点为可调度
设置kubectl自动补全
操作节点:k8s-master
$ yum install bash-completion -y
$ source /usr/share/bash-completion/bash_completion
$ source <(kubectl completion bash)
$ echo "source <(kubectl completion bash)" >> ~/.bashrc
使用kubeadm安装的集群,证书默认有效期为1年,可以通过如下方式修改为10年。
cd /etc/kubernetes/pki
# 查看当前证书有效期
for i in $(ls *.crt); do echo "===== $i ====="; openssl x509 -in $i -text -noout | grep -A 3 'Validity' ; done
有效期1年
拉取证书
[root@k8s-master /etc/kubernetes/pki]# git clone https://github.com/yuyicai/update-kube-cert.git
正克隆到 'update-kube-cert'...
remote: Enumerating objects: 140, done.
remote: Counting objects: 100% (28/28), done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 140 (delta 4), reused 6 (delta 3), pack-reused 112
接收对象中: 100% (140/140), 46.89 KiB | 0 bytes/s, done.
处理 delta 中: 100% (67/67), done.
进入目录执行
[root@k8s-master /etc/kubernetes/pki]# cd update-kube-cert/
[root@k8s-master /etc/kubernetes/pki/update-kube-cert]# ll
总用量 60
-rw-r--r-- 1 root root 1064 12月 3 13:34 LICENSE
-rw-r--r-- 1 root root 2760 12月 3 13:34 other.md
-rw-r--r-- 1 root root 2322 12月 3 13:34 other-zh_CN.md
-rw-r--r-- 1 root root 7318 12月 3 13:34 README.md
-rw-r--r-- 1 root root 7228 12月 3 13:34 README-zh_CN.md
-rw-r--r-- 1 root root 13285 12月 3 13:34 update-kubeadm-cert-crictl.sh
-rwxr-xr-x 1 root root 13068 12月 3 13:34 update-kubeadm-cert.sh
[root@k8s-master /etc/kubernetes/pki/update-kube-cert]# bash update-kubeadm-cert.sh all
CERTIFICATE EXPIRES
/etc/kubernetes/controller-manager.config Dec 2 03:47:48 2024 GMT
/etc/kubernetes/scheduler.config Dec 2 03:47:49 2024 GMT
/etc/kubernetes/admin.config Dec 2 03:47:47 2024 GMT
/etc/kubernetes/pki/ca.crt Nov 30 03:47:40 2033 GMT
/etc/kubernetes/pki/apiserver.crt Dec 2 03:47:41 2024 GMT
/etc/kubernetes/pki/apiserver-kubelet-client.crt Dec 2 03:47:42 2024 GMT
/etc/kubernetes/pki/front-proxy-ca.crt Nov 30 03:47:42 2033 GMT
/etc/kubernetes/pki/front-proxy-client.crt Dec 2 03:47:43 2024 GMT
/etc/kubernetes/pki/etcd/ca.crt Nov 30 03:47:44 2033 GMT
/etc/kubernetes/pki/etcd/server.crt Dec 2 03:47:44 2024 GMT
/etc/kubernetes/pki/etcd/peer.crt Dec 2 03:47:44 2024 GMT
/etc/kubernetes/pki/etcd/healthcheck-client.crt Dec 2 03:47:46 2024 GMT
/etc/kubernetes/pki/apiserver-etcd-client.crt Dec 2 03:47:46 2024 GMT
[2023-12-03T13:35:43.08+0800][INFO] backup /etc/kubernetes to /etc/kubernetes.old-20231203
[2023-12-03T13:35:43.09+0800][INFO] updating...
[2023-12-03T13:35:43.28+0800][INFO] updated /etc/kubernetes/pki/etcd/server.conf
[2023-12-03T13:35:43.46+0800][INFO] updated /etc/kubernetes/pki/etcd/peer.conf
[2023-12-03T13:35:43.58+0800][INFO] updated /etc/kubernetes/pki/etcd/healthcheck-client.conf
[2023-12-03T13:35:43.72+0800][INFO] updated /etc/kubernetes/pki/apiserver-etcd-client.conf
[2023-12-03T13:35:44.50+0800][INFO] restarted etcd
[2023-12-03T13:35:44.75+0800][INFO] updated /etc/kubernetes/pki/apiserver.crt
[2023-12-03T13:35:44.90+0800][INFO] updated /etc/kubernetes/pki/apiserver-kubelet-client.crt
[2023-12-03T13:35:45.10+0800][INFO] updated /etc/kubernetes/controller-manager.conf
[2023-12-03T13:35:45.26+0800][INFO] updated /etc/kubernetes/scheduler.conf
[2023-12-03T13:35:45.45+0800][INFO] updated /etc/kubernetes/admin.conf
[2023-12-03T13:35:45.47+0800][INFO] backup /root/.kube/config to /root/.kube/config.old-20231203
[2023-12-03T13:35:45.48+0800][INFO] copy the admin.conf to /root/.kube/config
[2023-12-03T13:35:45.48+0800][INFO] does not need to update kubelet.conf
[2023-12-03T13:35:45.69+0800][INFO] updated /etc/kubernetes/pki/front-proxy-client.crt
[2023-12-03T13:35:57.05+0800][INFO] restarted apiserver
[2023-12-03T13:35:57.93+0800][INFO] restarted controller-manager
[2023-12-03T13:35:58.92+0800][INFO] restarted scheduler
[2023-12-03T13:35:59.19+0800][INFO] restarted kubelet
[2023-12-03T13:35:59.20+0800][INFO] done!!!
CERTIFICATE EXPIRES
/etc/kubernetes/controller-manager.config Nov 30 05:35:45 2033 GMT
/etc/kubernetes/scheduler.config Nov 30 05:35:45 2033 GMT
/etc/kubernetes/admin.config Nov 30 05:35:45 2033 GMT
/etc/kubernetes/pki/ca.crt Nov 30 03:47:40 2033 GMT
/etc/kubernetes/pki/apiserver.crt Nov 30 05:35:44 2033 GMT
/etc/kubernetes/pki/apiserver-kubelet-client.crt Nov 30 05:35:44 2033 GMT
/etc/kubernetes/pki/front-proxy-ca.crt Nov 30 03:47:42 2033 GMT
/etc/kubernetes/pki/front-proxy-client.crt Nov 30 05:35:45 2033 GMT
/etc/kubernetes/pki/etcd/ca.crt Nov 30 03:47:44 2033 GMT
/etc/kubernetes/pki/etcd/server.crt Nov 30 05:35:43 2033 GMT
/etc/kubernetes/pki/etcd/peer.crt Nov 30 05:35:43 2033 GMT
/etc/kubernetes/pki/etcd/healthcheck-client.crt Nov 30 05:35:43 2033 GMT
/etc/kubernetes/pki/apiserver-etcd-client.crt Nov 30 05:35:43 2033 GMT
再次查询有效期为10年
集群验证
操作节点: 在master节点(k8s-master
)执行
$ kubectl get nodes #观察集群节点是否全部Ready
创建测试nginx服务
$ kubectl run test-nginx --image=nginx:alpine
查看pod是否创建成功,并访问pod ip测试是否可用
$ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-nginx-5bd8859b98-5nnnw 1/1 Running 0 9s 10.244.1.2 k8s-slave1 <none> <none>
$ curl 10.244.1.2
...
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
第二章
本章学习kubernetes的架构及工作流程,重点介绍如何使用Workload管理业务应用的生命周期,实现服务不中断的滚动更新,通过服务发现和集群内负载均衡来实现集群内部的服务间访问,并通过ingress实现外部使用域名访问集群内部的服务。
学习过程中会逐步对容器项目做k8s改造,从零开始编写所需的资源文件。通过本章的学习,学员会掌握高可用k8s集群的搭建,同时容器项目已经可以利用k8s的控制器、服务发现、负载均衡、配置管理等特性来实现生命周期的管理。
纯容器模式的问题
- 业务容器数量庞大,哪些容器部署在哪些节点,使用了哪些端口,如何记录、管理,需要登录到每台机器去管理?
- 跨主机通信,多个机器中的容器之间相互调用如何做,iptables规则手动维护?
- 跨主机容器间互相调用,配置如何写?写死固定IP+端口?
- 如何实现业务高可用?多个容器对外提供服务如何实现负载均衡?
- 容器的业务中断了,如何可以感知到,感知到以后,如何自动启动新的容器?
- 如何实现滚动升级保证业务的连续性?
- ......
容器调度管理平台
- Docker Swarm
- Mesos
- Google Kubernetes
2017年开始Kubernetes凭借强大的容器集群管理功能, 逐步占据市场,目前在容器编排领域一枝独秀
架构图
如何设计一个容器管理平台?
- 集群架构,管理节点分发容器到数据节点
- 如何部署业务容器到各数据节点
- N个数据节点,业务容器如何选择部署在最合理的节点
- 容器如何实现多副本,如何满足每个机器部署一个容器的模型
- 多副本如何实现集群内负载均衡
分布式系统,两类角色:管理节点和工作节点
核心组件
-
ETCD:分布式高性能键值数据库,存储整个集群的所有元数据
-
ApiServer: API服务器,集群资源访问控制入口,提供restAPI及安全访问控制
-
Scheduler:调度器,负责把业务容器调度到最合适的Node节点
-
Controller Manager:控制器管理,确保集群资源按照期望的方式运行
- Replication Controller
- Node controller
- ResourceQuota Controller
- Namespace Controller
- ServiceAccount Controller
- Token Controller
- Service Controller
- Endpoints Controller
-
kubelet:运行在每个节点上的主要的“节点代理”,脏活累活
- pod 管理:kubelet 定期从所监听的数据源获取节点上 pod/container 的期望状态(运行什么容器、运行的副本数量、网络或者存储如何配置等等),并调用对应的容器平台接口达到这个状态。
- 容器健康检查:kubelet 创建了容器之后还要查看容器是否正常运行,如果容器运行出错,就要根据 pod 设置的重启策略进行处理.
- 容器监控:kubelet 会监控所在节点的资源使用情况,并定时向 master 报告,资源使用数据都是通过 cAdvisor 获取的。知道整个集群所有节点的资源情况,对于 pod 的调度和正常运行至关重要
-
kube-proxy:维护节点中的iptables或者ipvs规则
-
kubectl: 命令行接口,用于对 Kubernetes 集群运行命令 命令行工具 (kubectl) | Kubernetes
静态Pod的方式:
## etcd、apiserver、controller-manager、kube-scheduler
$ kubectl -n kube-system get po
systemd服务方式:
$ systemctl status kubelet
kubectl:二进制命令行工具
理解集群资源
组件是为了支撑k8s平台的运行,安装好的软件。
资源是如何去使用k8s的能力的定义。比如,k8s可以使用Pod来管理业务应用,那么Pod就是k8s集群中的一类资源,集群中的所有资源可以提供如下方式查看:
$ kubectl api-resources
如何理解namespace:
命名空间,集群内一个虚拟的概念,类似于资源池的概念,一个池子里可以有各种资源类型,绝大多数的资源都必须属于某一个namespace。集群初始化安装好之后,会默认有如下几个namespace:
$ kubectl get namespaces
NAME STATUS AGE
default Active 84m
kube-node-lease Active 84m
kube-public Active 84m
kube-system Active 84m
kubernetes-dashboard Active 71m
- 所有NAMESPACED的资源,在创建的时候都需要指定namespace,若不指定,默认会在default命名空间下
- 相同namespace下的同类资源不可以重名,不同类型的资源可以重名
- 不同namespace下的同类资源可以重名
- 通常在项目使用的时候,我们会创建带有业务含义的namespace来做逻辑上的整合
kubectl的使用
类似于docker,kubectl是命令行工具,用于与APIServer交互,内置了丰富的子命令,功能极其强大。 Command line tool (kubectl) | Kubernetes
$ kubectl -h
$ kubectl get -h
$ kubectl create -h
$ kubectl create namespace -h
最小调度单元 Pod
docker调度的是容器,在k8s集群中,最小的调度单元是Pod(豆荚)
为什么引入Pod
-
与容器引擎解耦
Docker、Rkt。平台设计与引擎的具体的实现解耦
-
多容器共享网络|存储|进程 空间, 支持的业务场景更加灵活
Pod在集群中的形态
使用yaml格式定义Pod
pod-eladmin-api.yaml
apiVersion: v1
kind: Pod
metadata:
name: eladmin-api
namespace: luffy
labels:
app: eladmin-api
spec:
containers:
- name: eladmin-api
image: xx.xxx.xxx.xxx:5000/eladmin/eladmin-api:v1
env:
- name: DB_HOST # 指定数据库地址
value: "xx.xxx.xxx.xxx"
- name: DB_USER # 指定数据库连接使用的用户
value: "root"
- name: DB_PWD
value: "luffyAdmin!"
- name: REDIS_HOST
value: "xx.xxx.xxx.xxx"
- name: REDIS_PORT
value: "6379"
ports:
- containerPort: 8000
# http://www.wetools.com/yaml/
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "eladmin-api",
"namespace": "luffy",
"labels": {
"app": "eladmin-api"
}
},
"spec": {
"containers": [
{
"name": "eladmin-api",
"image": "xx.xxx.xxx.xxx:5000/eladmin/eladmin-api:v1",
"env": [
{
"name": "DB_HOST",
"value": "xx.xxx.xxx.xxx"
},
{
"name": "DB_USER",
"value": "root"
},
{
"name": "DB_PWD",
"value": "luffyAdmin!"
},
{
"name": "REDIS_HOST",
"value": "xx.xxx.xxx.xxx"
},
{
"name": "REDIS_PORT",
"value": "6379"
}
],
"ports": [
{
"containerPort": 8000
}
]
}
]
}
}
apiVersion | 含义 |
---|---|
alpha | 进入K8s功能的早期候选版本,可能包含Bug,最终不一定进入K8s |
beta | 已经过测试的版本,最终会进入K8s,但功能、对象定义可能会发生变更。 |
stable | 可安全使用的稳定版本 |
v1 | stable 版本之后的首个版本,包含了更多的核心对象 |
apps/v1 | 使用最广泛的版本,像Deployment、ReplicaSets都已进入该版本 |
支持的资源类型与apiVersion
kubectl api-resources
快速获得资源和版本
$ kubectl explain pod
$ kubectl explain Pod.apiVersion
创建和访问Pod
## 创建namespace, namespace是逻辑上的资源池
kubectl create namespace luffy
## 使用指定文件创建Pod
kubectl create -f pod-eladmin-api.yaml
## ImagePullBackOff,创建镜像拉取所用的密钥信息
kubectl -n luffy create secret docker-registry registry-172-21-65-226 --docker-username=admin --docker-password=admin --docker-email=admin@admin.com --docker-server=172.21.65.226:5000
## 给pod配置上述密钥
apiVersion: v1
kind: Pod
metadata:
name: eladmin-api
namespace: luffy
labels:
app: eladmin-api
spec:
imagePullSecrets:
- name: registry-172-21-65-22
containers:
- name: eladmin-api
...
## 删除pod重建,两种方式
kubectl -n luffy delete pod eladmin-api
kubectl delete -f pod-eladmin-api.yaml
## 查看pod,可以简写po
## 所有的操作都需要指定namespace,如果是在default命名空间下,则可以省略
$ kubectl -n luffy get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
eladmin-api 1/1 Running 0 11m 10.244.1.15 k8s-slave1
## 回顾流程
## 使用Pod Ip访问服务,3306和8002
$ curl 10.244.1.15:8000/auth/code
## 进入容器,执行初始化, 不必到对应的主机执行docker exec
$ kubectl -n luffy exec -ti eladmin-api bash
/ # env
Infra容器
登录k8s-slave1
节点
$ nerdctl -n k8s.io ps -a|grep eladmin-api ## 发现有二个容器
## 其中包含eladmin容器以及pause容器
## 为了实现Pod内部的容器可以通过localhost通信,每个Pod都会启动pause容器,然后Pod内部的其他容器的网络空间会共享该pause容器的网络空间(Docker网络的container模式),pause容器只需要hang住网络空间,不需要额外的功能,因此资源消耗极低。
$ crictl -r "unix:///var/run/containerd/containerd.sock" pull 172.21.65.226:5000/eladmin/eladmin-api:v1
$ crictl -r "unix:///var/run/containerd/containerd.sock" rmi xxxxx
$ nerdctl pull 172.21.65.226:5000/eladmin/eladmin-api:v1
$ crictl -r "unix:///var/run/containerd/containerd.sock" logs -f 5627a65b98416
查看pod详细信息
## 查看pod调度节点及pod_ip
$ kubectl -n luffy get pods -o wide
## 查看完整的yaml
$ kubectl -n luffy get po eladmin-api -o yaml
## 查看pod的明细信息及事件
$ kubectl -n luffy describe pod eladmin-api
Troubleshooting and Debugging
#进入Pod内的容器
$ kubectl -n <namespace> exec <pod_name> -c <container_name> -ti /bin/sh
#查看Pod内容器日志,显示标准或者错误输出日志
$ kubectl -n <namespace> logs -f <pod_name> -c <container_name>
更新服务版本
$ kubectl apply -f pod-eladmin-api.yaml
删除Pod服务
#根据文件删除
$ kubectl delete -f pod-eladmin-api.yaml
#根据pod_name删除
$ kubectl -n <namespace> delete pod <pod_name>
Pod多容器
pod-eladmin.yaml
apiVersion: v1
kind: Pod
metadata:
name: eladmin
namespace: luffy
labels:
app: eladmin
spec:
imagePullSecrets:
- name: registry-172-21-65-226
containers:
- name: eladmin-api
image: 172.21.65.226:5000/eladmin/eladmin-api:v1
env:
- name: DB_HOST # 指定数据库地址
value: "172.21.65.226"
- name: DB_USER # 指定数据库连接使用的用户
value: "root"
- name: DB_PWD
value: "luffyAdmin!"
- name: REDIS_HOST
value: "172.21.65.226"
- name: REDIS_PORT
value: "6379"
ports:
- containerPort: 8000
- name: eladmin-web
image: 172.21.65.226:5000/eladmin/eladmin-web:v1
ports:
- containerPort: 80