63 KiB
深入刨析Kubernetes
来源:原 mongodb 集合
t_blog· 整理日期:2026-08-25 分类 ID:2022051619278900000000000002· 排序:5 · 文章数:14
目录
- 第2章 Docker
- 第3章 设计与架构
- kubernetes etcd安装
- 第4章 kubeadm
- 第5章 编排原理
- 第7章 网络原理
- 第6章 存储原理
- 第8章 调度与资源管理
- 第10章 资源
- 第11章 权限控制
- 基于虚拟网卡共有网络k8s集群搭建
- kubernetes 二进制安装master
- kubernetes Calico 配置
- kubernetes 二进制安装worker
1. 第2章 Docker
bid: 2022051619278900000000000003
kubernetes 第2章 Docker
docker network
# show network command: bridge, host, none
docker network ls
# bridge
# host
# none
docker 项目最核心的原理是,为带创建的用户进程
重新认识linux容器
1.Linux Namespace 的隔离能力 2.Linux Cgroups的限制能力 3.基于rootfs的文件系统 其中用到了chroot 和 pivot_root 两个系统调用切换进程目录的能力 docker 在镜像的设计中引入了layer的概念 docker镜像使用的rootfs往往由多个layer组成。 这些layer 分:
- ro+wh layer
- rw layer
- init layer
- init层是docker项目单独生成的内部层,专门存放/etc/hosts,/etc/resolv.conf等信息。用户 commit时 init层并不会提交。提交的时rw层。
Dockerfile
# Comment
INSTRUCTION arguments
FROM python:2.7-slim
WORKDIR /app
ADD . /app
RUN pip install --trusted-host pypi.python.org -r requirements.txt
EXPOSE 80
ENV NAME World
CMD ["python", "app.py"]
# dockerfile默认提供了一个隐式的ENTRYPOINT INSTRUCTION
即 /bin/sh -c
所以Docker容器的启动进程为ENTRYPOINT, 而不是CMD
而CMD命令为Dockerfile指定python app.py 为该容器进程
CMD的内容就是ENTRYPOINT 的参数
实际上在容器中运行的进程为 /bin/sh -c "python app.py"
Linux Namespace 隔离机制
Linux Namespace虽然看不见摸不到,但是一个进程的Namespace信息在宿主机上是确实存在的,并且以文件的形式存在。
$ docker inspect --format '{{ .State.pid }}' 4ddf4542324
25686
此时,可以查看宿主机文件
$ls -l /proc/25686/ns
可以看出一个进程是有多个Namespace的,存放于该目录下。
这就意味着,一个进程可以选择加入某个Namespace中,这就是docker exec 原理
docker Volume
在chroot之前,宿主机的文件目录对容器进程是可见的,我们只需要在rootfs准备好后,在执行chroot之前,把Volume指定的宿主机目录挂载到指定容器目录即可。 Volume里信息不会被docker commit提交。
2. 第3章 设计与架构
bid: 2022051809471000000000000005
kubernetes 第3章 设计与架构
Kubernetes 设计与架构
容器实际上是由,Linux Namespace,Linux Cgroup,rootfs 这三种技术构建出来的。 不难看出一个运行中linux的容器其实可以被一分为二的: 1.挂载到/var/lib/docker/aufs/mnt上的rootfs,这一部分被称为容器镜像,是容器的静态视图。 2.一个由Namespace+Cgroups构成的隔离环境,这一部分被称为容器运行时,是容器的动态视图。 容器编排项目:compose+Swarm和Kubarnetes容器编排工具。
Kubernetes的核心能力与项目定位
Kubernetes 的本质是平台的平台,即一个用来帮助用户构建上层平台的基础平台。 Pod是Kubernetes 中最基础的单元 声明式API是kubernetes最核心的设计理念,通过
apiserver
etcd
cri
kubectl
kubelet
proxy
3. kubernetes etcd安装
bid: 2022053111285300000000000018
删除kubeadm 残留信息
yum remove -y kubelet kubeadm kubectl
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
etcd 集群安装
1.1 服务器规划
etcd-1
etcd-2
etcd-3
1.2 资源准备
wget https://github.com/kubernetes/kubernetes/archive/refs/tags/v1.23.8.tar.gz
从gethub源码中的go.mod可以看出,etcd的版本依赖是v3.5.0
然后我去下载etcd-v3.5.0
wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz
1.3 cfssl证书生成工具准备 cfssl是一个开源的证书管理工具,使用json文件生成证书,相比openssl更方便使用。 找任意一台服务器操作,这里用Master1节点。
#创建目录存放cfssl工具
mkdir /software-cfssl
#下载相关工具
cd /software-cfssl
wget -q --timestamping https://storage.googleapis.com/kubernetes-the-hard-way/cfssl/1.4.1/linux/cfssl https://storage.googleapis.com/kubernetes-the-hard-way/cfssl/1.4.1/linux/cfssljson
cd /software-cfssl/
chmod +x *
mv cfssl cfssljson /usr/local/bin
1.4 自签证书颁发机构(CA)
# 创建工作目录
mkdir -p ~/TLS/{etcd,k8s}
cd ~/TLS/etcd/
# 生成自签CA配置
cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"www": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat > ca-csr.json << EOF
{
"CN": "etcd CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai"
}
]
}
EOF
- 生成自签CA证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
- ca的有效证书查看
openssl x509 -in ca.pem -noout -text
1.5 签发etcd https证书
# 使用自签CA
cat > server-csr.json << EOF
{
"CN": "etcd",
"hosts": [
"49.233.4.79",
"43.138.55.43",
"43.138.73.106",
"10.0.16.3",
"10.0.8.13",
"127.0.0.1"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai"
}
]
}
EOF
- 生成证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
- 查看有效期
openssl x509 -in server.pem -noout -text
``
**1.5** 部署etcd集群
mkdir /usr/local/etcd-v3.5.0/{bin,cfg,ssl} -p
tar -xf etcd-v3.4.9-linux-amd64.tar.gz
mv etcd-v3.4.9-linux-amd64/{etcd,etcdctl} /usr/local/etcd-v3.5.0/bin/
---
# 创建etcd配置文件
cat > /usr/local/etcd-v3.5.0/conf/etcd.conf << EOF
#[Member]
ETCD_NAME="etcd-1" # 需要修改
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://49.233.4.79:2380"
ETCD_LISTEN_CLIENT_URLS="https://49.233.4.79:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://49.233.4.79:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://49.233.4.79:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://49.233.4.79:2380,etcd-2=https://43.138.55.43:2380,etcd-3=https://138.73.106:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
# etc-1 为new,etcd-2/2为existing,网上很多文章都是直接copy不改,是不好使的
EOF
---
# systemd管理etcd
cat > /usr/lib/systemd/system/etcd.service << EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
EnvironmentFile=/usr/local/etcd-v3.5.0/conf/etcd.conf
User=root # 此处必须要指定用户,要不启动会报错
ExecStart=/usr/local/etcd-v3.5.0/bin/etcd \
--cert-file=/usr/local/etcd-v3.5.0/ssl/server.pem \
--key-file=/usr/local/etcd-v3.5.0/ssl/server-key.pem \
--peer-cert-file=/usr/local/etcd-v3.5.0/ssl/server.pem \
--peer-key-file=/usr/local/etcd-v3.5.0/ssl/server-key.pem \
--trusted-ca-file=/usr/local/etcd-v3.5.0/ssl/ca.pem \
--peer-trusted-ca-file=/usr/local/etcd-v3.5.0/ssl/ca.pem \
--logger=zap
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
---
将master1节点所有生成的文件拷贝到节点2和节点3
xsync etcd-v3.5.0
---
修改节点2,节点3 ,etcd.conf配置文件中的节点名称和当前服务器IP:
---
启动etcd并设置开机自启
---
检查etcd集群状态
---
etcd问题排查(日志)
less /var/log/message
journalctl -u etcd
journalctl -xe
etcd 默认数据目录
/var/lib/etcd/
# 只有第一次启动时候,发生"msg":"request cluster ID mismatch"
rm -rf /usr/local/etcd-v3.5.0/data
systemctl stop etcd
systemctl start etcd
etcd 启动
etcd --config-file /usr/local/etcd-v3.5.0/conf/etcd.conf.yml
etcd 后台启动
nohup etcd --config-file /usr/local/etcd-v3.5.0/conf/etcd.conf.yml >/usr/local/etcd-v3.5.0/log/etcd.log 2>&1 &
测试
ETCDCTL_API=2 etcdctl
ETCDCTL_API=3 etcdctl
---
关于客户端和CA证书的问题,etcdctl 是 客户端,而我们签发的证书都是服务端证书,所以访问服务端时候必须把z
--cacert=/usr/local/etcd-v3.5.0/ssl/ca.pem --cert=/usr/local/etcd-v3.5.0/ssl/server.pem --key=/usr/local/etcd-v3.5.0/ssl/server-key.pem
---
## 4. 第4章 kubeadm
<sub>bid: `2022060613040400000000000019`</sub>
## kubernetes 第4章 kubeadm
### k8s 安装相关 doc
---
[apiDoc](https://kubernetes.io/docs/reference/config-api/)
[docker centos install doc](https://docs.docker.com/engine/install/centos/)
## 4.1 安装背景
---
腾讯云服务器,3台2G四核的不同网段的轻量云服务器(特价买的)。
因为轻量云服务器采用的是VPC网络,所以通过ip addr 命令可以看到并没有公网网址。
和一个网段私有网络不同,这里是需要公网ip的,所以做了一个临时的虚拟网卡:
`4.1.1` 创建临时网卡先应付:
# 每台机器都要做(临时网卡做法,永久性的暂时没测试)
ifconfig eth0:1 49.233.4.79 netmask 255.255.255.0 up
ifconfig eth0:1 43.138.55.43 netmask 255.255.255.0 up
ifconfig eth0:1 43.138.73.106 netmask 255.255.255.0 up
`4.1.2` 腾讯云有两个网络访问安全的设置:
# 添加 安全组 规则 放行所有6443 TCP端口
# 防火前 添加 规则 ,放行 node1 node2 node3 的6443 TCP网络
`4.1.3` hostname修改
# hostname 修改
hostnamectl set-hostname xx
`4.1.4` 设置3台机器的网络连接:
# 修改 /etc/hosts
vi /etc/hosts
# 将以下内容添加即可
49.233.4.79 node1
43.138.55.43 node2
43.138.73.106 node3
# ping
ping node3
`4.1.5` 将 SELinux 设置为 permissive 模式(相当于将其禁用)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
`4.1.6` 关闭swap
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab
`4.1.7` 允许 iptables 检查桥接流量
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system
`4.1.8` 删除以前残留的网络设置信息
rm -rf /etc/cni/net.d/*
rm -rf /var/lib/cni/calico
systemctl restart kubelet
systemctl stop kubelet
systemctl stop docker
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/*
rm -rf /etc/cni/
ifconfig cni0 down
ifconfig flannel.1 down
ifconfig docker0 down
iptb
ip link delete cni0
ip link delete flannel.1
systemctl start docker
systemctl start kubelet
### 4.2 kubeadm install
---
记录一次使用kubeadm安装的操作。
kubeadm:直接在宿主机上运行kubelet,然后使用容器部署其他k8s组件的妥协方式。
`4.2.1` docker install
Preflight check
拿到云服务器(centos 7.6)后,首先安装了docker
49.233.4.79
2705483506 43.138.55.43
3584667696 43.138.73.106
# 查看docker-ce的版本
yum list docker-ce --showduplicates | sort -r
# 安装docker
# yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io docker-compose-plugin
yum install docker-ce-20.10.17-3.el7 docker-ce-cli-20.10.17-3.el7 containerd.io docker-compose-plugin
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
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
`4.2.2` kubelet/kubectl/kubeadm download
# 指定版本号最好
yum -y install kubelet-1.23.7-0 kubeadm-1.23.7-0 kubectl-1.23.7-0
# 如果原来存在多个版本,请删除,因为默认是使用高版本的,会导致无法加入node
yum -y remove kubeadm* kubelet* kubectl*
systemctl enable kubelet.service
# 修改 docker 的cgroup
# 添加以下内容
vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
# 重启docker
systemctl restart docker
docker info | grep Cgroup
### 4.3 kubeadm init
# 创建集群,其他默认就可以,需要指定集群公网地址和CIDR局域网网段
kubeadm init --apiserver-advertise-address 49.233.4.79 --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
# token 24h 过期
kubeadm token create --print-join-command
# 查看集群master节点
kubectl describe node node1
# 查看集群pods,我们会发现,coredns 一直处于Pending状态,这是符合预期的,因为我们还没有安装集群插件
kubectl get pods -A
# 安装集群插件 flannel
# https://github.com/flannel-io/flannel/blob/master/Documentation/kube-flannel.yml
kubectl apply -f kube-flannel.yaml
# 安装集群网络插件
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
# 再查看集群pods,一定要先安装网络插件,再去添加集群节点哦。
kubectl get pods -A
# 加入worker节点
# 由于不在一个内网,集群间通讯默认走内网ip,因此需要借助公网ip,通过iptables转换
iptables -t nat -A OUTPUT -d -j DNAT --to-destination 青云内网ip
# 然后 kubeadm join 在其他node处添加进来。
kubeadm join 49.233.4.79:6443 --token xx.xxx \
--discovery-token-ca-cert-hash sha256:xxxxxxx
# 到这一步集群节点就算完事了。
### 4.4 ETCD
---
`4.4.1` etcd ca
# etcd 作为数据库 也有自己的ca,kubeadm 安装etcd时ca是存入以下路径
/etc/kubernetes/pki/etcd/
`4.4.2` etcd comman
1. 查看ETCD集群中运行的ETCD pod
kubectl get pod -n kube-system | grep etcd
2. 进入ETCD pod容器
kubectl exec -it etcd-node1 -n kube-system -- /bin/sh
3. 设置环境变量为v3
export ETCDCTL_API=3
4. 查看 member list
ETCDCTL_API=3 etcdctl \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
member list
check perf
4. 查看 key 需要加上cert才可以
etcdctl get /registry/pods/kube-system/kube-flannel-ds-vnhrw
5. 未查询简单化,添加别名
# 别名列表
alias -p
# 添加别名
alias cls=clear
# 删除别名
unalias 别名
alias etc="/usr/local/bin/etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key"
6. 查询所有的key
etcdctl get / --prefix --keys-only
7. 查询flnanel配置
etcdctl get /registry/configmaps/kube-system/kube-flannel-cfg
ETCD_ENABLE_V2=true
ETCDCTL_API=2 etcdctl ls /coreos.com/network/subnets/
ETCDCTL_API=2 etcdctl cluster-health
ETCDCTL_API=2 etcdctl member list
ETCDCTL_API=3 etcdctl member list
ETCDCTL_API=3 etcdctl check perf
### 4.5 各种错误的解决方法。
---
# 最典型的就是版本不统一导致的安装错误
[ERROR CRI]: container runtime is not running: output: time="2022-06-13T10:26:24+08:00" level=fatal msg="unable to determine runtime API version: rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial unix /var/run/containerd/containerd.sock: connect: no such file or directory\""
详细过程如下:
这个原因吧 是一开始 直接yum -y install docker 发生的错,后来用docker-ce 就直接修复了
[ERROR KubeletVersion]: the kubelet version is higher than the control plane version. This is not a supported version skew and may lead to a malfunctional cluster. Kubelet version: "1.24.1" Control plane version: "1.23.7"
yum -y remove kubelet
yum -y install kubelet-1.23.7 kubeadm-1.23.7
kubeadm init 时候会发现被墙了。
I0613 12:39:59.679221 18038 checks.go:859] pulling: k8s.gcr.io/coredns/coredns:v1.8.6
[preflight] Some fatal errors occurred:
[ERROR ImagePull]: failed to pull image k8s.gcr.io/kube-apiserver:v1.23.7: output: Error response from daemon: Get "https://k8s.gcr.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
解决方案: https://www.cnblogs.com/lifan1998/p/14326761.html
DOCKERHUB_URL=registry.aliyuncs.com/google_containers
---
kubeadm init 时候kubelet check 出错
[kubelet-check] It seems like the kubelet isn't running or healthy.
[kubelet-check] The HTTP call equal to 'curl -sSL http://localhost:10248/healthz' failed with error: Get "http://localhost:10248/healthz": dial tcp [::1]:10248: connect: connection refused.
使用 journalctl -xeu kubelet查看错误信息,基本上是docker 的cgroup和k8s的cgroup不一致导致的。
修改 docker 的cgroup
解决方法
# 添加以下内容
vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
# 重启docker
systemctl restart docker
docker info | grep Cgroup
# 重新初始化
kubeadm reset # 先重置
### 上述master节点完成后进入,worker node安装
---
# 确保和主节点的kubeadm版本相同
yum list --showduplicates kubeadm
yum -y install kubeadm-1.23.7-0 kubelet-1.23.7-0 kubectl-1.23.7-0
systemctl enable kubelet.service
### /proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1
错误
[ERROR FileContent–proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1
[preflight] If you know what you are doing, you can make a check non-fatal with --ignore-preflight-errors=...
解决方案
echo “1” >/proc/sys/net/bridge/bridge-nf-call-iptables
---
## 5. 第5章 编排原理
<sub>bid: `2022060717000500000000000021`</sub>
## kubernetes 第5章 编排原理
### 污点
---
`taints:污点,定义在节点上,是键值数据`
`tolerations:容忍度,定义在pod上,可以定义能容忍哪些污点`
taints:
- effect: NoSchedule 不会被调度
key: node-role.kubernetes.io/master
- effect: PreferNoSchedule 尽量不调度
key: node-role.kubernetes.io/master
- effect: NoExecute 驱逐节点
key: node-role.kubernetes.io/master
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
一个 toleration和一个 taint 相"匹配"是指它们有一样的key和effect
operator 默认是 Equal ,即value 相等才匹配
`master节点默认是有污点的可以通过以下命令查看`
kubectl describe nodes node1 | grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
该污点表示,不会被调度。
kubectl describe nodes node2 | grep Taints
Taints: <none>
`如何在master节点发布pod呢`
---
## 6. 第7章 网络原理
<sub>bid: `2022060814410000000000000024`</sub>
##
### 7.2 深入解析容器跨主机网络
---
为了解决容器跨主机通信问题,就一定要从Flannel项目说起。
Flannel项目目前提供了三种实现:
(1)VXLAN
(2)host-gw了。
(3)UDP
UDP是最早的支持的一种方式,但是,性能较差,已经弃用,但这种方式简单直接,也是最容易理解的一种容器跨主机网络实现。
Flannel会在宿主机上创建一些列路由规则,flannel0
flannel0是基于CIDR/16的,而docker0,eth0是基于CIDR/24的。并且flannel0设备类型很有意思,他是一个基于TUN设备(tunnel设备)
在linux中tunnel设备是在一种第三层(网络层)工作的virtual device。他的功能也非常简单,就是在操作系统内核和用户应用程序之间传递ip包。
当操作系统,将一个Ip包发送给一个flannel0设备之后,flannel0会把这个ip包交给创建该设备的应用程序,也就是Flannel进程,这是一个内核态到用户态的流动方向。
反之,如果Flannel进程,向flannel0设备发送了一个ip包,这个ip包会出现在 宿主机network stack 中,根据宿主机的路由表进行下一步处理。这是用户态向内核态的流动方向。
还有一个重要概念subnet子网:事实上,一台主机上的所有容器都会被分配一个CIDR/24的子网,而主机和子网的映射关系保存在k8s的分布式存储etcd当中。
// 查看keys
$ etcdctl ls /coreos.com/network/subnets
/coreos.com/network/subnets/100.96.1.0-24
/coreos.com/network/subnets/100.96.2.0-24
/coreos.com/network/subnets/100.96.3.0-24
// 获取public ip
$ etcdctl get /coreos.com/network/subnets/100.96.2.0-24
{"PublicIP": "10.168.0.3"}
以上过程的总结:
容器确定source ip和 target ip,如果他们在一个CIDR/24下,则走的直连规则,如果不是一个子网段,则会把ip包通过docker0进入到宿主机ip route表中进行匹配,然后进入到flannel0设备中,flannel0 通过tunnel 把ip包转给flannel1d进程,然后通过etcd查询target的共有ip,并将ip包发出。
当然,采用UDP得以实现的原因是,每台宿主机flannelid都监听着一个8285端口。
当然这种方式,性能很差,差在tunnel设备需要三次用户态和内核态的切换,很肥资源。
这也是Flannel 后来支持VXLAN的模式成为主流的网络解决方案。
### VXLAN(virtual extensible LAN 虚拟可扩展局域网)
---
是linux本来就支持的网络虚拟化技术。
VXLAN可以在完全在内核态上实现封装和解封的工作,从而构建UDP模式相似的网络。
VXLAN是在二层网络上构建出的隧道模式,只不过对他进行封装和解封的对象是二层数据帧(ethernet frame),而且这个工作全部是在内核里完成,(因为VXLAN就是linux内核的一个模块)
但是为了解决发送时IP包并不知道MAC,所以需要维护一个ARP表
可以通过命令去查看
$ ip neigh show dev flannel.1
### 7.3 kubernetes网络模型与CNI网络插件
---
7.2的流程,是k8s对容器网络的处理方法。只不过k8s是通过一个叫做CNI的接口维护了一个单独的网桥来代替docker0.默认的设备名称cni0.
具体内容就不细说了,
### 7.4 解读kubernetes 三层网络方案 host-gw
--
### 7.5 解读kubernetes 三层
--
---
## 7. 第6章 存储原理
<sub>bid: `2022060814418900000000000023`</sub>
kubernetes 第6章 存储原理
---
## 8. 第8章 调度与资源管理
<sub>bid: `2022060814420100000000000025`</sub>
## kubernetes 第8章 调度与资源管理
### 8.1 kubernetes 资源模型
---
- 可压缩资源(compressiable resources)
CPU,当他不足时,Pod只会饥饿,不会退出
- 不可压缩资源(imcompressiable resources)
内存,当他不足时,Pod会因为OOM被内核结束。
由于Pod是可以由多个Containner组成,而每个Containner都是一个进程,所以Pod整体的资源配置是由Container所有进程资源配置累加的,同时资源配置是需要配置在Container上的。
此外,k8s是允许,CPU设置成分数的,cpu=0.5或者cpu=500m这样的写法,才是k8s的内部通用表示法。
内存的单位自然就是byte,注意区分MB和Mib
**※** 1MiB 1024x1024 1Mb=1000x1000
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
关于limits和requests
区别:
调度时候,kube-scheduler只会按照requests的值去计算。
而在真正设置Cgroups的时候,kubelet会按照limits去计算。
### qosclass类型
---
如果只定义了limits,那么k8s默认会将requests与limits设置一样,
qosclass字段会被k8s自动设置成Guaranteed
当Pod不满足Guaranteed,但至少有一个container设置了requests,k8s会将qosclass设置成Burstable
如果一个Pod既没有设置limits也没有设置requests,Qos的类型为BestEffort
**作用**
当宿主机资源紧张的时候,kubelet对Pod进行资源回收(Eviction)时候需要用到。具体来说,宿主机上不可压缩资源资源短缺时候,就有可能触发Eviction
目前Eviction的默认值如下:
memory.available<100Mi
nodefs.available<10%
nodefs.inodesFree<5%
imagefs.avaialble<15%
kubelet中是可以对上述Eviction进行配置的。
配置时,有两种模式Soft和Hard,
而k8s计算Eviction的阈值数据来源,是通过Cgroup读取的值和cAdsivor监控到的数据。
当宿主机的Eviction阈值达到后,会进入MemoryPressure或者DiskPressure状态,从而避免新的Pod被调度到这个宿主机。
**Eviction**
发生Eviction按照,BestEffort->Burstable(超过requests的容器)->Guaranteed
**cpuset**
我们可以通过cpuset将容器绑定到某个CPU的核上,而不是像cpushare共享cpu计算能力。这样操作系统在cpu直接的切换会大大减少。
### 8.2 kubernetes 默认调度器
---
- default scheduler
默认调度器的主要职责是,为创建出来的Pod需找一个最合适的节点。
Node selection in kube-scheduler
kube-scheduler selects a node for the pod in a 2-step operation:
1. Filtering
2. Scoring
根据算法选出,可调度的list,在根据算法从中选出最优。
Predicate算法,检查每个节点是否可用
Priority算法,给每个节点打分,得分最高的就是最终的调度结果。
而,scheduler对Pod的调度成功体现在,他的spec.nodeName字段填上调度结果的节点名字。
### 8.3 kubernetes 默认调度器调度策略
---
- 调度策略
- [doc](https://kubernetes.io/docs/reference/scheduling/policies/)
1. GeneralPredicates
2. 与Volume相关的过滤策略
NoDiskConflict检查多个Pod声明的PV是否有冲突,比如AWS EBS类型的Volume不允许被两个Pod同时使用。
MaxPDVolumeCountPredicate检查一个节点某个类型的PV是否超过一定数量。
3. 宿主机相关的过滤策略
NodeMemoryPressurePredicate
4. Pod相关的过滤策略
PodAffinityPredicate
亲密性affinity和反亲密性anti-affinity。
## 8.4 kubernetes 默认调度器优先级和抢占机制
---
Priority和Preemption解决的是Pod调度失败后该怎么办的问题。
提交一个priorityclass定义:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globleDefault: false
description: "~~~~"
默认的Pod的priority的value是0
globleDefault是false意味着,不是默认的,需要在pod声明指定
因为scheduler中维护了一个调度队列,当Pod中priority高的就有可能提前出队列,从而更早的完成调度过程。
当一个高priority的Pod调度失败后,scheduler的抢占Preemption能力就会触发。
scheduler 在调度队列中实现了两个不同的队列:
activeQ和unschedulableQ
activeQ中的Pod都是下一次调度周期需要调度的对象
unschedulableQ存放的都是调度失败的Pod。
当一个unschedulableQ发生更新后,k8s
---
## 9. 第10章 资源
<sub>bid: `2022061515517700000000000028`</sub>
## 1. ingress来龙去脉
---
[doc](https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/)
- Ingress-nginx quick start
[quick start](https://kubernetes.github.io/ingress-nginx/deploy/#quick-start)
K8s集群对外暴露服务的方式目前只有三种:
- Loadblancer
- Nodeport
- ingress
- headerless
### ingress介绍
---
ingress由两部分组成
- ingress
指的是k8s中的一个api对象,一般用yaml配置。作用是定义请求如何转发到service的规则,可以理解为配置模板。
- ingress controller
具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发。
ingress-controller并不是k8s自带的组件,实际上ingress-controller只是一个统称,用户可以选择不 同的ingress-controller实现
目前,由k8s维护的ingress-controller只有google云的GCE与ingress-nginx两个,其他还有很多第三方维护的ingress-controller
### ingress-controller 安装
[参照](https://blog.csdn.net/weixin_38797137/article/details/124251698)
# 先现在 配置文件
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.0/deploy/static/provider/cloud/deploy.yaml
# 由于国内被墙,有几个镜像是下载不下来的,所以修改deploy.yaml
vi deploy.yaml
# /image 查找镜像
# 修改controller:v1.2.0
bitnami/nginx-ingress-controller:1.2.0
# 修改kube-webhook-certgen
registry.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1
# /externalTrafficPolicy
# 修改externalTrafficPolicy = Cluster
# 最后 apply
kubectl apply -f deploy.yaml
### ingress tls 证书替换
// [可以参考 linux 下的 nginx 证书使用](https://cloud.tencent.com/document/product/400/35244)
[root@node1 ~]# kubectl create secret tls https-secret2023 --cert=/usr/local/kubernetes/secret/violin-home.cn_bundle.crt --key=/usr/local/kubernetes/secret/violin-home.cn.key -n devops
[root@node1 ~]# kubectl get secret -A
[root@node1 ~]# kubectl edit ingress violin-ingress -n devops
## 2. Service
---
[doc](https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/)
[root@node1 ~]# kubectl get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d21h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 2d21h
`先了解以下参与k8s网络的角色`
- kube-dns
- kube-proxy
- kube-flannel-ds
- coredns
- cni0
- controller
---
## 10. 第11章 权限控制
<sub>bid: `2022061710512100000000000001`</sub>
## RBAC规则
---
### 概念
RBAC模型(Role-Based Access Control:基于角色的访问控制)
在RBAC模型里面,有3个基础组成部分,分别是:用户、角色和权限。
- User(用户):每个用户都有唯一的UID识别,并被授予不同的角色
- Role(角色):不同角色具有不同的权限
- Permission(权限):访问权限
# user -> role <- Permission
张三 管理员 增删改查
李四 普通用户 查
王五 普通用户 查
设置角色,然后对角色进行权限设置,然后将用户和角色关联即可。
用户和权限没有必然关系,是通过角色去控制的
### kubernetes 中的RBAC
RBAC规则包含ServiceAccount、ClusterRole、ClusterRoleBinding三类YAML文件,即三种对象
- **Service Account**
是面向命名空间的:
apiVersion: v1
kind: ServiceAccount
metadata:
name: beckend-serviceaccount
namespace: kube-users
- **ClusterRole**
是面向整个集群所有命名空间的
ClusterRole的一条规则由apiGroups、resources、verbs共同组成
ClusterRole 用来描述 一个角色和他所拥有的权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-readonly
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list
- watch
- apiGroups:
- metrics.k8s.io
resources:
- pods
verbs:
- get
- list
- watch
- ClusterRoleBinding
是面向整个集群所有命名空间的
ClusterRoleBinding中subjects是访问API的主体
subjects包含users、groups、service accounts三种类型
我们使用的是ServiceAccount类型
ClusterRoleBinding 描述的是将 ServiceAccount(用户)和 ClusterRole(角色)jin'xing
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: namespace-readonly-sa
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: namespace-readonly
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: ServiceAccount
name: system:serviceaccounts:kube-users
---
## 11. 基于虚拟网卡共有网络k8s集群搭建
<sub>bid: `2022062320127000000000000005`</sub>
### linux
---
- port set
在腾讯云控制面对相应端口进行放行
TCP 6443
UDP 8472
TCP 30000-32767
- SELinux 设置为 permissive 模式(相当于将其禁用)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
- 关闭swap
# 临时关闭swap分区,当前会话生效,重启失效
swapoff -a
# 永久关闭swap分区
sed -ri 's/.*swap.*/#&/' /etc/fstab
- 所有机器都要做
echo "1" >/proc/sys/net/bridge/bridge-nf-call-iptables
echo 1 > /proc/sys/net/ipv4/ip_forward
vi /etc/sysctl.conf
net.ipv4.ip_forward = 1
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
sudo sysctl --system
### 创建网卡
由于PVC网卡上是没有public ip 的,需要我们自定义网卡
# 每台机器都要做(临时网卡做法,永久性的暂时没测试)
# ifconfig eth0:1 49.233.4.79 netmask 255.255.255.0 up
# ifconfig eth0:1 43.138.55.43 netmask 255.255.255.0 up
# ifconfig eth0:1 43.138.73.106 netmask 255.255.255.0 up
ifconfig eth0:1 49.233.4.79
# 永久生效
cat > /etc/sysconfig/network-scripts/ifcfg-eth0:1 <<EOF
BOOTPROTO=static
DEVICE=eth0:1
IPADDR=<你的公网IP>
PREFIX=32
TYPE=Ethernet
USERCTL=no
ONBOOT=yes
EOF
### 版本信息
---
kubernetes, kubelet, kubectl, kubeadm version
v1.23.7
### 修改kubelet( per machine)
---
# 此文件安装kubeadm后就存在了
vim /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
# 注意,这步很重要,如果不做,节点仍然会使用内网IP注册进集群
# 在末尾添加参数 --node-ip=公网IP
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS --node-ip=<公网IP>
### 编写启动配置文件
---
# 添加配置文件,注意替换下面的IP
cat > kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.23.7
apiServer:
certSANs:
- master #请替换为hostname
- xx.xx.xx.xx #请替换为公网IP
- xx.xx.xx.xx #请替换为私网IP
- 10.96.0.1
controlPlaneEndpoint: xx.xx.xx.xx:6443 #替换为公网IP
imageRepository: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images 已有镜像仓库,此处删除。
networking:
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
---
apiVersion: kubeproxy-config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
featureGates:
SupportIPVSProxyMode: true
mode: ipvs
EOF
### kubeadm 创建master节点
---
kubeadm init --config=kubeadm-config.yaml
### 修改kube-apiserver参数(master,只修改注释项,其余的不要动)
---
# 修改两个信息,添加--bind-address和修改--advertise-address
vim /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=xx.xx.xx.xx # 修改为公网IP
- --bind-address=0.0.0.0 # 新增参数
- --allow-privileged=true
### 安装flannel网络插件(只在master 主节点执行)
---
# 1、下载flannel配置文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
修改 kube-flannel.yml 内容,如下:
net-conf.json: |
{
"Network": "10.244.0.0/16", # 这里是kubeadm-config.yaml配置的podsnetwork
"Backend": {
"Type": "vxlan"
}
}
containers:
- name: kube-flannel
image: quay.io/coreos/flannel:v0.14.0
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
- --public-ip=$(PUBLIC_IP) # 新增
- --iface=eth0 # 新增
resources:
requests:
cpu: "100m"
memory: "50Mi"
limits:
cpu: "100m"
memory: "50Mi"
securityContext:
privileged: false
capabilities:
add: ["NET_ADMIN", "NET_RAW"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: PUBLIC_IP #新增
valueFrom: #新增
fieldRef: #新增
fieldPath: status.podIP #新增
### 创建网络
---
kubectl apply -f kube-flannel.yml
### 将worker节点加入即可
---
### 关于分布式存储
---
- rook
customresourcedefinition.apiextensions.k8s.io/cephblockpoolradosnamespaces.ceph.rook.io created
clusterrole.rbac.authorization.k8s.io/cephfs-csi-nodeplugin created
clusterrolebinding.rbac.authorization.k8s.io/cephfs-csi-provisioner-role created
role.rbac.authorization.k8s.io/cephfs-external-provisioner-cfg created
rolebinding.rbac.authorization.k8s.io/cephfs-csi-provisioner-role-cfg created
serviceaccount/rook-ceph-cmd-reporter created
configmap/rook-ceph-operator-config created
deployment.apps/rook-ceph-operator created
---
## 12. kubernetes 二进制安装master
<sub>bid: `2022070116141100000000000006`</sub>
### 事前准备
---
如果以前有安装过, 请清理掉
ll /usr/lib/systemd/system/kube*
systemctl stop kube-apiserver
systemctl stop kube-controller-manager
systemctl stop kubelet
systemctl stop kube-proxy
systemctl stop kube-scheduler
目录准备
mkdir -p /usr/local/kubernetes/{bin,conf,ssl,logs}
### kube-apiserver 安装
---
`生成自签CA配置`
cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat > ca-csr.json << EOF
{
"CN": "kubernetes CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai",
"O": "k8s",
"OU": "system"
}
]
}
EOF
生成CA
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
---
`给apiServer签发证书`
cat > server-csr.json << EOF
{
"CN": "kubernetes",
"hosts": [
"10.244.0.1",
"10.0.0.1",
"127.0.0.1",
"49.233.4.79",
"43.138.55.43",
"43.138.73.106",
"10.0.16.3",
"10.0.8.13",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai",
"O": "k8s",
"OU": "system"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server
生成token
head -c 16 /dev/urandom | od -An -t x | tr -d ' '
cat > /usr/local/kubernetes/conf/token.csv << EOF
f41424f202b2c2e71da40ce20d32f1d2,kubelet-bootstrap,10001,"system:node-bootstrapper"
EOF
---
cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/usr/local/kubernetes/conf/kube-apiserver.conf
ExecStart=/usr/local/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
---
vi kube-apiserver.conf
KUBE_APISERVER_OPTS="--logtostderr=false \
--v=2 \
--log-dir=/usr/local/kubernetes/logs \
--etcd-servers=https://49.233.4.79:2379,https://43.138.55.43:2379,https://43.138.73.106:2379 \
--bind-address=49.233.4.79 \
--secure-port=6443 \
--advertise-address=49.233.4.79 \
--allow-privileged=true \
--service-cluster-ip-range=10.0.0.0/16 \
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \
--authorization-mode=RBAC,Node \
--enable-bootstrap-token-auth=true \
--token-auth-file=/usr/local/kubernetes/conf/token.csv \
--service-node-port-range=30000-32767 \
--kubelet-client-certificate=/usr/local/kubernetes/ssl/server.pem \
--kubelet-client-key=/usr/local/kubernetes/ssl/server-key.pem \
--tls-cert-file=/usr/local/kubernetes/ssl/server.pem \
--tls-private-key-file=/usr/local/kubernetes/ssl/server-key.pem \
--client-ca-file=/usr/local/kubernetes/ssl/ca.pem \
--service-account-key-file=/usr/local/kubernetes/ssl/ca-key.pem \
--service-account-issuer=api \
--service-account-signing-key-file=/usr/local/kubernetes/ssl/server-key.pem \
--etcd-cafile=/usr/local/etcd-v3.5.0/ssl/ca.pem \
--etcd-certfile=/usr/local/etcd-v3.5.0/ssl/server.pem \
--etcd-keyfile=/usr/local/etcd-v3.5.0/ssl/server-key.pem \
--requestheader-client-ca-file=/usr/local/kubernetes/ssl/ca.pem \
--proxy-client-cert-file=/usr/local/kubernetes/ssl/server.pem \
--proxy-client-key-file=/usr/local/kubernetes/ssl/server-key.pem \
--requestheader-allowed-names=kubernetes \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-group-headers=X-Remote-Group \
--requestheader-username-headers=X-Remote-User \
--enable-aggregator-routing=true \
--audit-log-maxage=30 \
--audit-log-maxbackup=3 \
--audit-log-maxsize=100 \
--audit-log-path=/usr/local/kubernetes/logs/k8s-audit.log"
---
# 刷新设置,并设置开机启动,查看status
systemctl daemon-reload
systemctl start kube-apiserver
systemctl enable kube-apiserver
systemctl status kube-apiserver -l
### kube-controller-manager 安装
---
`创建配置文件`
cat > /usr/local/kubernetes/conf/kube-controller-manager.conf << EOF
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/usr/local/kubernetes/logs \\
--leader-elect=true \\
--kubeconfig=/usr/local/kubernetes/conf/kube-controller-manager.kubeconfig \\
--bind-address=127.0.0.1 \\
--allocate-node-cidrs=true \\
--cluster-cidr=10.244.0.0/16 \\
--service-cluster-ip-range=10.0.0.0/16 \\
--cluster-signing-cert-file=/usr/local/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/usr/local/kubernetes/ssl/ca-key.pem \\
--root-ca-file=/usr/local/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/usr/local/kubernetes/ssl/ca-key.pem \\
--cluster-signing-duration=87600h0m0s"
EOF
---
`生成证书`
cd /usr/local/kubernetes/ssl
cat > kube-controller-manager-csr.json << EOF
{
"CN": "system:kube-controller-manager",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai",
"O": "system:masters",
"OU": "System"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
ll
`生成kubeconfig文件`
KUBE_CONFIG="/usr/local/kubernetes/conf/kube-controller-manager.kubeconfig"
KUBE_APISERVER="https://49.233.4.79:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/usr/local/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-controller-manager \
--client-certificate=/usr/local/kubernetes/ssl/kube-controller-manager.pem \
--client-key=/usr/local/kubernetes/ssl/kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user=kube-controller-manager \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
ll /usr/local/kubernetes/conf
---
`systemd管理controller-manager`
cat > /usr/lib/systemd/system/kube-controller-manager.service << EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/usr/local/kubernetes/conf/kube-controller-manager.conf
ExecStart=/usr/local/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
---
`启动并设置开机自启`
systemctl daemon-reload
systemctl start kube-controller-manager
systemctl enable kube-controller-manager
systemctl status kube-controller-manager -l
### kube-scheduler 安装
---
`创建配置文件`
cat > /usr/local/kubernetes/conf/kube-scheduler.conf << EOF
KUBE_SCHEDULER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/usr/local/kubernetes/logs \\
--leader-elect \\
--kubeconfig=/usr/local/kubernetes/conf/kube-scheduler.kubeconfig \\
--bind-address=127.0.0.1"
EOF
---
`生成kubeconfig文件`
cd /usr/local/kubernetes/ssl
cat > kube-scheduler-csr.json << EOF
{
"CN": "system:kube-scheduler",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai",
"O": "system:masters",
"OU": "System"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
ll
---
`生成kubeconfig文件 `
KUBE_CONFIG="/usr/local/kubernetes/conf/kube-scheduler.kubeconfig"
KUBE_APISERVER="https://49.233.4.79:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/usr/local/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-scheduler \
--client-certificate=/usr/local/kubernetes/ssl/kube-scheduler.pem \
--client-key=/usr/local/kubernetes/ssl/kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user=kube-scheduler \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
---
`systemd管理scheduler`
cat > /usr/lib/systemd/system/kube-scheduler.service << EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/usr/local/kubernetes/conf/kube-scheduler.conf
ExecStart=/usr/local/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
---
`启动并设置开机启动`
systemctl daemon-reload
systemctl start kube-scheduler
systemctl enable kube-scheduler
systemctl status kube-scheduler -l
---
### kubectl 安装
---
`生成kubectl连接集群的证书`
cd /usr/local/kubernetes/ssl
cat > admin-csr.json <<EOF
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai",
"O": "system:masters",
"OU": "System"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
ll
---
`生成kubeconfig文件`
rm -rf /root/.kube
mkdir /root/.kube
KUBE_CONFIG="/root/.kube/config"
KUBE_APISERVER="https://49.233.4.79:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/usr/local/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials cluster-admin \
--client-certificate=/usr/local/kubernetes/ssl/admin.pem \
--client-key=/usr/local/kubernetes/ssl/admin-key.pem \
--embed-certs=true \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user=cluster-admin \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
ll
---
`通过kubectl工具查看当前集群组件状态`
[root@k8s-master1 ssl]# kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-2 Healthy {"health":"true","reason":""}
etcd-0 Healthy {"health":"true","reason":""}
etcd-1 Healthy {"health":"true","reason":""}
如上说明Master节点组件运行正常。
---
`授权kubelet-bootstrap用户允许请求证书`
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap
---
### kubelet
---
`kubelet是 kubernetes 工作节点上的一个代理组件,运行在每个节点上。由于我的三台服务都是工作节点,所以也都需要装kubelet和kube-proxy`
`apiserver <-> kubelet <-> pod`
---
`创建服务`
cat > /usr/lib/systemd/system/kubelet.service << EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
[Service]
EnvironmentFile=/usr/local/kubernetes/conf/kubelet.conf
ExecStart=/usr/local/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
---
`创建服务配置文件`
cat > /usr/local/kubernetes/conf/kubelet.conf << EOF
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/usr/local/kubernetes/logs \\
--network-plugin=cni \\
--hostname-override=k8s-master1 \\
--kubeconfig=/usr/local/kubernetes/conf/kubelet.kubeconfig \\
--bootstrap-kubeconfig=/usr/local/kubernetes/conf/bootstrap.kubeconfig \\
--config=/usr/local/kubernetes/conf/kubelet-config.yml \\
--cert-dir=/usr/local/kubernetes/ssl \\
--pod-infra-container-image=k8s.gcr.io/pause:3.6"
EOF
---
`创建k8s kubelet资源文件`
cat > /usr/local/kubernetes/conf/kubelet-config.yml << EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 0.0.0.0
port: 10250
readOnlyPort: 10255
cgroupDriver: systemd
clusterDNS:
- 10.0.0.2
clusterDomain: cluster.local
failSwapOn: false
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /usr/local/kubernetes/ssl/ca.pem
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
nodefs.inodesFree: 5%
maxOpenFiles: 1000000
maxPods: 110
EOF
---
KUBE_CONFIG="/usr/local/kubernetes/conf/bootstrap.kubeconfig"
KUBE_APISERVER="https://49.233.4.79:6443" # apiserver IP:PORT
TOKEN="f41424f202b2c2e71da40ce20d32f1d2" # 与token.csv里保持一致 /usr/local/kubernetes/conf/token.csv
# 生成 kubelet bootstrap kubeconfig 配置文件
kubectl config set-cluster kubernetes \
--certificate-authority=/usr/local/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials "kubelet-bootstrap" \
--token=${TOKEN} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user="kubelet-bootstrap" \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
ll
---
systemctl daemon-reload
systemctl stop kubelet
systemctl start kubelet
systemctl enable kubelet
systemctl status kubelet -l
---
kubectl get csr
kubectl certificate approve node-csr-KbHieprZUMOvTFMHGQ1RNTZEhsSlT5X6wsh2lzfUry4
certificatesigningrequest.certificates.k8s.io/node-csr-KbHieprZUMOvTFMHGQ1RNTZEhsSlT5X6wsh2lzfUry4 approved
---
`部署kube-proxy`
cat > /usr/local/kubernetes/conf/kube-proxy.conf << EOF
KUBE_PROXY_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/usr/local/kubernetes/logs \\
--config=/usr/local/kubernetes/conf/kube-proxy-config.yml"
EOF
---
cat > /usr/local/kubernetes/conf/kube-proxy-config.yml << EOF
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
metricsBindAddress: 0.0.0.0:10249
clientConnection:
kubeconfig: /usr/local/kubernetes/conf/kube-proxy.kubeconfig
hostnameOverride: k8s-master1
clusterCIDR: 10.244.0.0/16
EOF
---
cd /usr/local/kubernetes/ssl
cat > kube-proxy-csr.json << EOF
{
"CN": "system:kube-proxy",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai",
"O": "k8s",
"OU": "System"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
ll
---
`生成kube-proxy.kubeconfig文件`
KUBE_CONFIG="/usr/local/kubernetes/conf/kube-proxy.kubeconfig"
KUBE_APISERVER="https://49.233.4.79:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/usr/local/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-proxy \
--client-certificate=/usr/local/kubernetes/ssl/kube-proxy.pem \
--client-key=/usr/local/kubernetes/ssl/kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
---
cat > /usr/lib/systemd/system/kube-proxy.service << EOF
[Unit]
Description=Kubernetes Proxy
After=network.target
[Service]
EnvironmentFile=/usr/local/kubernetes/conf/kube-proxy.conf
ExecStart=/usr/local/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
---
systemctl daemon-reload
systemctl stop kube-proxy
systemctl start kube-proxy
systemctl enable kube-proxy
systemctl status kube-proxy -l
---
## 13. kubernetes Calico 配置
<sub>bid: `2022070223079600000000000007`</sub>
### 官方网站
---
该插件与kubernetes版本对应。
https://projectcalico.docs.tigera.io/archive/v3.20/getting-started/kubernetes/requirements
### 安装
---
安装文档
https://projectcalico.docs.tigera.io/archive/v3.23/getting-started/kubernetes/self-managed-onprem/onpremises#install-calico-with-kubernetes-api-datastore-50-nodes-or-less
### 填坑
---
``
rm -rf /etc/cni/net.d/*
rm -rf /var/lib/cni/calico
systemctl restart kubelet
systemctl stop kubelet
systemctl stop docker
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/*
rm -rf
ifconfig cni0 down
ifconfig flannel.1 down
ifconfig docker0 down
iptb
ip link delete cni0
ip link delete flannel.1
systemctl start docker
systemctl start kubelet
`关于污点和容忍`
kubectl taint node k8s-master1 node.kubernetes.io/not-ready-
``
cat > apiserver-to-kubelet-rbac.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
- pods/log
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubernetes
EOF
kubectl apply -f apiserver-to-kubelet-rbac.yaml
ー--
---
## 14. kubernetes 二进制安装worker
<sub>bid: `2022070314528700000000000008`</sub>
### kubelet
---
`kubelet是 kubernetes 工作节点上的一个代理组件,运行在每个节点上。由于我的三台服务都是工作节点,所以也都需要装kubelet和kube-proxy`
`apiserver <-> kubelet <-> pod`
---
`创建服务`
cat > /usr/lib/systemd/system/kubelet.service << EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
[Service]
EnvironmentFile=/usr/local/kubernetes/conf/kubelet.conf
ExecStart=/usr/local/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
---
`创建服务配置文件`
cat > /usr/local/kubernetes/conf/kubelet.conf << EOF
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/usr/local/kubernetes/logs \\
--network-plugin=cni \\
--hostname-override=k8s-node3 \\
--kubeconfig=/usr/local/kubernetes/conf/kubelet.kubeconfig \\
--bootstrap-kubeconfig=/usr/local/kubernetes/conf/bootstrap.kubeconfig \\
--config=/usr/local/kubernetes/conf/kubelet-config.yml \\
--cert-dir=/usr/local/kubernetes/ssl \\
--pod-infra-container-image=k8s.gcr.io/pause:3.6"
EOF
---
`创建k8s kubelet资源文件`
cat > /usr/local/kubernetes/conf/kubelet-config.yml << EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 0.0.0.0
port: 10250
readOnlyPort: 10255
cgroupDriver: systemd
clusterDNS:
- 10.0.0.2
clusterDomain: cluster.local
failSwapOn: false
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /usr/local/kubernetes/ssl/ca.pem
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
nodefs.inodesFree: 5%
maxOpenFiles: 1000000
maxPods: 110
EOF
---
KUBE_CONFIG="/usr/local/kubernetes/conf/bootstrap.kubeconfig"
KUBE_APISERVER="https://49.233.4.79:6443" # apiserver IP:PORT
TOKEN="47d803a011a25fee21cc2fa434c391aa" # 与token.csv里保持一致 /opt/kubernetes/cfg/token.csv
# 生成 kubelet bootstrap kubeconfig 配置文件
kubectl config set-cluster kubernetes \
--certificate-authority=/usr/local/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials "kubelet-bootstrap" \
--token=${TOKEN} \
--kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
--cluster=kubernetes \
--user="kubelet-bootstrap" \
--kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}
---
systemctl daemon-reload
systemctl stop kubelet
systemctl start kubelet
systemctl enable kubelet
systemctl status kubelet -l
---