Files
knowledge-base/AI/mechine learning/深入刨析Kubernetes.md
T
2026-08-25 22:28:36 +08:00

2129 lines
63 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 深入刨析Kubernetes
> 来源:原 mongodb 集合 `t_blog` · 整理日期:2026-08-25
> 分类 ID:`2022051619278900000000000002` · 排序:5 · 文章数:14
## 目录
1. [第2章 Docker](#第2章-docker)
2. [第3章 设计与架构](#第3章-设计与架构)
3. [kubernetes etcd安装](#kubernetes-etcd安装)
4. [第4章 kubeadm](#第4章-kubeadm)
5. [第5章 编排原理](#第5章-编排原理)
6. [第7章 网络原理](#第7章-网络原理)
7. [第6章 存储原理](#第6章-存储原理)
8. [第8章 调度与资源管理](#第8章-调度与资源管理)
9. [第10章 资源](#第10章-资源)
10. [第11章 权限控制](#第11章-权限控制)
11. [基于虚拟网卡共有网络k8s集群搭建](#基于虚拟网卡共有网络k8s集群搭建)
12. [kubernetes 二进制安装master](#kubernetes-二进制安装master)
13. [kubernetes Calico 配置](#kubernetes-calico-配置)
14. [kubernetes 二进制安装worker](#kubernetes-二进制安装worker)
---
## 1. 第2章 Docker
<sub>bid: `2022051619278900000000000003`</sub>
## kubernetes 第2章 Docker
### docker network
---
[参考1](https://baijiahao.baidu.com/s?id=1730776907492640810&wfr=spider&for=pc)
[参照2](https://blog.csdn.net/gui951753/article/details/79210535)
# 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
---
[doc](https://docs.docker.com/engine/reference/builder/)
# 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章 设计与架构
<sub>bid: `2022051809471000000000000005`</sub>
## 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安装
<sub>bid: `2022053111285300000000000018`</sub>
### 删除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配置
```bash
cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"www": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
```
```bash
cat > ca-csr.json << EOF
{
"CN": "etcd CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "ShangHai",
"ST": "ShangHai"
}
]
}
EOF
```
- 生成自签CA证书
```bash
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
```
- ca的有效证书查看
```bash
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
- 生成证书
```bash
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
```
- 查看有效期
```bash
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
---