提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

  • kubernetes 已经在 1.24 版本中删除了 docker-shim 这个组件,使得 docker 无法对接 1.24 以后版本的
    kubernetes PS:之前都是 kubernetes 团队维护 docker-shim 组件,因为一些历史原因,放弃了
    docker-shim 之前写过一篇 基于 containerd 二进制部署 k8s-v1.23.3,总体体验下来,觉得自己被
    docker 惯坏了 containerd 的上手很不习惯,原生的 ctr 命令不好用,build 镜像也依赖 buildkit 服务
    对于菜鸡的我来说,containerd 就好比手动挡的车,只有老司机才能驾驭,我更喜欢自动挡多一点
    这篇文章,都是使用了当前最新版本的组件来部署,仅供学习使用
    实际的生产也好,公司环境也好,还是要选择当前的稳定版本,直接使用最新版会过于激进
    另外,如果有需求部署 kubernetes 的话,在不喜欢 containerd 的前提下,可以直接使用 cri-dockerd ,这样在后期如果需要提升到 1.24 以上版本的 kubernetes 就可以减少很多烦心事
    虽然,不管是升级容器运行时版本还是升级 kubernetes 版本,都会很糟心,只不过,能少一个是一个 [手动狗头.jpg]

提示:以下是本篇文章正文内容,下面案例可供参考

kubernetesv1.26.3
etcdv3.5.7
cfsslv1.6.3
docker23.0.1
cri-dockerdv0.3.1
cniv1.1.1
calicov3.25.0

大部分的组件都是通过 github 下载的,下面整合了下载链接,可以开始前先准备好二进制文件

# kubernetes 二进制文件
https://dl.k8s.io/v1.26.3/kubernetes-server-linux-amd64.tar.gz
# etcd 二进制文件
https://github.com/etcd-io/etcd/releases/download/v3.5.7/etcd-v3.5.7-linux-amd64.tar.gz
# cfssl 二进制文件
https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl_1.6.3_linux_amd64
# cfssljson 二进制文件
https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssljson_1.6.3_linux_amd64
# docker 二进制文件
https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/static/stable/x86_64/docker-23.0.1.tgz
# cri-dockerd 二进制文件
https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.1/cri-dockerd-0.3.1.amd64.tgz
IP角色
192.168.11.147master/worker
192.168.11.148master/worker
192.168.11.149master/worker

一般情况下,master 节点也会复用成 worker 节点,毕竟机器也挺贵的 如果有特殊要求,不希望 master
节点运行容器的话,这里需要注意一些场景 metrics-server 服务获取节点资源使用情况时,需要保证和 apiserver之间的网络可以互通
如果 master 节点不部署容器,理论上只需要部署网络插件来互通网络,实际上我没有尝试过,因为我穷,我都是 master 节点复用 worker 节点
我只尝试过 master 节点复用 worker 节点,但是 master节点不调度容器的场景,因为我的网络插件都是以容器的方式运行的

开始整活

挑选一个节点作为操作节点,我这边就按照顺序,选择了 192.168.11.147 这个节点来进行后面的操作

环境准备
创建干活的目录

这个目录,主要是建立一些模板文件,然后直接通过分发和 ssh 的方式来部署,减少频繁切换节点的操作 这里利用了 shell
变量的方式来操作的,如果终端退出过,需要重新定义 work_dir 这个变量,否则后面的其他操作会导致目录不存在的报错

work_dir='/data/k8s-work-dir'
mkdir -p ${work_dir}/{bin,images,pkg,tmp/{ssl,service}}

节点免密操作

静默生成 ssh 证书

ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa -q

分发 ssh 证书到所有节点,包含操作节点本身,下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do ssh-copy-id ${ip_head}.${i};done

关闭防火墙

下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
ssh ${ip_head}.${i} "systemctl disable firewalld"; \
ssh ${ip_head}.${i} "systemctl stop firewalld"; \
done

关闭 selinux

下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
ssh ${ip_head}.${i} "setenforce 0"; \
ssh ${ip_head}.${i} "sed -i 's/SELINUX=[a-z].*/SELINUX=disabled/g' /etc/selinux/config"; \
done

有返回 setenforce: SELinux is disabled 这样的内容,说明 selinux
已经被关闭过了,不需要理会,继续往下操作

关闭 swap 分区

下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
ssh ${ip_head}.${i} "swapoff -a"; \
ssh ${ip_head}.${i} "sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab"; \
done

开启内核模块

下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
ssh ${ip_head}.${i} "modprobe ip_vs"; \
ssh ${ip_head}.${i} "modprobe ip_vs_rr"; \
ssh ${ip_head}.${i} "modprobe ip_vs_wrr"; \
ssh ${ip_head}.${i} "modprobe ip_vs_sh"; \
ssh ${ip_head}.${i} "modprobe nf_conntrack"; \
ssh ${ip_head}.${i} "modprobe nf_conntrack_ipv4"; \
ssh ${ip_head}.${i} "modprobe br_netfilter"; \
ssh ${ip_head}.${i} "modprobe overlay"; \
done

避免服务器宕机重启后没有开启上面的内核模块,使用下面的方法来保证重启后会自动加载内核模块

cat << EOF > ${work_dir}/tmp/service/k8s-modules.conf
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
nf_conntrack_ipv4
br_netfilter
overlay
EOF

分发文件并启动内核模块加载服务 下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
scp ${work_dir}/tmp/service/k8s-modules.conf ${ip_head}.${i}:/etc/modules-load.d/; \
ssh ${ip_head}.${i} "systemctl enable systemd-modules-load"; \
ssh ${ip_head}.${i} "systemctl restart systemd-modules-load"; \
ssh ${ip_head}.${i} "systemctl is-active systemd-modules-load"; \
done

返回active表示自动加载模块服务启动成功

配置内核参数

以下的参数适用于 3.x 和 4.x 系列的内核

cat << EOF > ${work_dir}/tmp/service/kubernetes.conf
# 开启数据包转发功能(实现vxlan)
net.ipv4.ip_forward=1
# iptables对bridge的数据进行处理
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-arptables=1
# 关闭tcp_tw_recycle,否则和NAT冲突,会导致服务不通
net.ipv4.tcp_tw_recycle=0
# 不允许将TIME-WAIT sockets重新用于新的TCP连接
net.ipv4.tcp_tw_reuse=0
# socket监听(listen)的backlog上限
net.core.somaxconn=32768
# 最大跟踪连接数,默认 nf_conntrack_buckets * 4
net.netfilter.nf_conntrack_max=1000000
# 禁止使用 swap 空间,只有当系统 OOM 时才允许使用它
vm.swappiness=0
# 计算当前的内存映射文件数。
vm.max_map_count=655360
# 内核可分配的最大文件数
fs.file-max=6553600
# 持久连接
net.ipv4.tcp_keepalive_time=600
net.ipv4.tcp_keepalive_intvl=30
net.ipv4.tcp_keepalive_probes=10
EOF

分发文件并加载内核参数

下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
scp ${work_dir}/tmp/service/kubernetes.conf ${ip_head}.${i}:/etc/sysctl.d/; \
ssh ${ip_head}.${i} "sysctl -p /etc/sysctl.d/kubernetes.conf"; \
done

清空 iptables 规则

下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
ssh ${ip_head}.${i} "iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat"; \
ssh ${ip_head}.${i} "iptables -P FORWARD ACCEPT"; \
done

配置 ca 证书

cat << EOF > ${work_dir}/tmp/ssl/ca-config.json
{
  "signing": {
    "default": {
      "expiry": "876600h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "876600h"
      }
    }
  }
}
EOF
cat << EOF > ${work_dir}/tmp/ssl/ca-csr.json
{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShangHai",
      "L": "ShangHai",
      "O": "k8s",
      "OU": "System"
    }
  ],
  "ca": {
    "expiry": "876600h"
 }
}
EOF

准备 cfssl 工具

我提前下载好了 cfssl 工具,放在了 ${work_dir}/bin 目录下了,大家要注意自己放的路径

mv ${work_dir}/bin/cfssl_1.6.3_linux_amd64 ${work_dir}/bin/cfssl
mv ${work_dir}/bin/cfssljson_1.6.3_linux_amd64 ${work_dir}/bin/cfssljson
chmod +x ${work_dir}/bin/cfssl*

创建 ca 证书

不指定路径的情况下,生成的证书和查找的证书都是基于当前路径,如果有出现证书文件不存在,检查一下路径是否有添加以及路径是否正确

${work_dir}/bin/cfssl gencert -initca ${work_dir}/tmp/ssl/ca-csr.json | \
${work_dir}/bin/cfssljson -bare ${work_dir}/tmp/ssl/ca

部署 master 组件

部署 etcd 组件

准备 etcd 二进制文件

我提前下载好了 etcd 二进制文件,放在了 ${work_dir}/bin 目录下了,大家要注意自己放的路径

cd ${work_dir}/bin && \ tar xf etcd-v3.5.7-linux-amd64.tar.gz

下面的 ip 记得替换成自己的节点 ip

需要部署 etcd 组件的节点 ip 都需要在证书文件内记录下来 注意 json 格式,最后一个 ip 后面不要有 , 逗号

配置 etcd 证书

cat << EOF > ${work_dir}/tmp/ssl/etcd-csr.json
{
  "CN": "etcd",
  "hosts": [
    "127.0.0.1",
    "192.168.11.147",
    "192.168.11.148",
    "192.168.11.149"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShangHai",
      "L": "ShangHai",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

创建 etcd 证书

${work_dir}/bin/cfssl gencert \
-ca=${work_dir}/tmp/ssl/ca.pem \
-ca-key=${work_dir}/tmp/ssl/ca-key.pem \
-config=${work_dir}/tmp/ssl/ca-config.json \
-profile=kubernetes ${work_dir}/tmp/ssl/etcd-csr.json | \
${work_dir}/bin/cfssljson -bare ${work_dir}/tmp/ssl/etcd

配置 etcd 为 systemctl 管理

下面的 ip 记得替换成自己的节点 ip

etcd 参数

创建 systemctl 启动模板

注:下面的 \ 不要改成 \ ,这是因为会被 EOF 转义,所以要在前面加一个转义,这样生成的文件里面,每一行都会带有一个 \

cat << EOF > ${work_dir}/tmp/service/kube-etcd.service.template
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory=##etcdDataPath##
ExecStart=##etcdBin##/etcd \\
  --wal-dir= \\
  --data-dir=##etcdDataPath## \\
  --name=etcd-##etcdHost## \\
  --cert-file=##sslPath##/etcd.pem \\
  --key-file=##sslPath##/etcd-key.pem \\
  --peer-cert-file=##sslPath##/etcd.pem \\
  --peer-key-file=##sslPath##/etcd-key.pem \\
  --trusted-ca-file=##sslPath##/ca.pem \\
  --peer-trusted-ca-file=##sslPath##/ca.pem \\
  --initial-advertise-peer-urls=https://##etcdHost##:2380 \\
  --listen-peer-urls=https://##etcdHost##:2380 \\
  --listen-client-urls=https://##etcdHost##:2379,http://127.0.0.1:2379 \\
  --advertise-client-urls=https://##etcdHost##:2379 \\
  --initial-cluster-token=etcd-cluster-0 \\
  --initial-cluster=##etcdNodes## \\
  --initial-cluster-state=new \\
  --snapshot-count=50000 \\
  --auto-compaction-retention=1 \\
  --auto-compaction-mode=periodic \\
  --max-request-bytes=10485760 \\
  --quota-backend-bytes=8589934592
Restart=always
RestartSec=15
LimitNOFILE=65536
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target
EOF

生成各个 etcd 节点的 systemctl 启动文件

下面的 ip 记得替换成自己的节点 ip

etcdNodes 要改成所有 etcd 节点的 ip,注意最后一个 ip 后面没有 , 逗号
–initial-cluster 参数的格式为:<–name 参数>=https://<etcd 节点 ip>:2380 ,如果等于号前面的内容和 --name 参数 参数不一致,会导致 etcd 集群初始化失败 etcdBin 是 etcd 二进制文件的路径
etcdDataPath 是 etcd 数据存储路径 sslPath 是 etcd 证书存储路径

ip_head='192.168.11';for i in 147 148 149;do \
etcdHost="${ip_head}.${i}"; \
etcdNodes="etcd-192.168.11.147=https://192.168.11.147:2380,etcd-192.168.11.148=https://192.168.11.148:2380,etcd-192.168.11.149=https://192.168.11.149:2380"; \
etcdBin='/data/etcd-data/bin'; \
etcdDataPath='/data/etcd-data/data'; \
sslPath='/etc/kubernetest/ssl'; \
sed -e "s|##etcdHost##|${etcdHost}|g" -e "s|##etcdBin##|${etcdBin}|g" -e "s|##etcdDataPath##|${etcdDataPath}|g" -e "s|##sslPath##|${sslPath}|g" -e "s|##etcdNodes##|${etcdNodes}|g" ${work_dir}/tmp/service/kube-etcd.service.template > ${work_dir}/tmp/service/kube-etcd.service.${etcdHost}; \
done

文件并启动 etcd 集群

下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
etcdHost="${ip_head}.${i}"; \
ssh ${etcdHost} "mkdir -p ${etcdBin} ${sslPath}"; \
ssh ${etcdHost} "mkdir -p ${etcdDataPath} -m 700"; \
scp ${work_dir}/tmp/ssl/{ca*.pem,etcd*.pem} ${etcdHost}:${sslPath}/; \
scp ${work_dir}/tmp/service/kube-etcd.service.${etcdHost} ${etcdHost}:/usr/lib/systemd/system/kube-etcd.service; \
scp ${work_dir}/bin/etcd-v3.5.7-linux-amd64/{etcd,etcdctl} ${etcdHost}:${etcdBin}/; \
ssh ${etcdHost} "systemctl enable kube-etcd && systemctl start kube-etcd --no-block"; \
done

验证 etcd 集群

下面的 ip 记得替换成自己的节点 ip

ip_head='192.168.11';for i in 147 148 149;do \
etcdHost="${ip_head}.${i}"; \
ssh ${etcdHost} "ETCDCTL_API=3 ${etcdBin}/etcdctl \
                 --endpoints=https://${etcdHost}:2379 \
                 --cacert=${sslPath}/ca.pem \
                 --cert=${sslPath}/etcd.pem \
                 --key=${sslPath}/etcd-key.pem \
                 endpoint health"; \
done

预期返回类似如下的回显,ip 显示的是大家自己机器的 ip,只要看到 is healthy: successfully 说明节点是正常的

https://192.168.11.147:2379 is healthy: successfully committed proposal: took = 6.156014ms
https://192.168.11.148:2379 is healthy: successfully committed proposal: took = 7.048715ms
https://192.168.11.149:2379 is healthy: successfully committed proposal: took = 19.618844ms

部署 apiserver 组件

准备 apiserver 二进制文件

我提前下载好了 apiserver 二进制文件,放在了 ${work_dir}/bin 目录下了,大家要注意自己放的路径

cd ${work_dir}/bin/ && \
tar xf kubernetes-server-linux-amd64.tar.gz

这里分享一个小技巧,解压出来的 kubernetes 二进制文件里面包含了 kubeadm,使用 kubeadm 命令可以看到当前版本的
kubernetes 的镜像版本,包含了 etcd ,pause 和 coredns

${work_dir}/bin/kubernetes/server/bin/kubeadm config images list

可以看到,官方配套的组件版本如下:

registry.k8s.io/kube-apiserver:v1.26.3
registry.k8s.io/kube-controller-manager:v1.26.3
registry.k8s.io/kube-scheduler:v1.26.3
registry.k8s.io/kube-proxy:v1.26.3
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.6-0
registry.k8s.io/coredns/coredns:v1.9.3

配置 apiserver 证书

下面的 ip 记得替换成自己的节点 ip

和 etcd 组件一样,把所有的 apiserver 节点 ip 都要写进去 如果有 SLB 等高可用 ip,也要写进去
(我这里没有做高可用,就不写了)
10.88.0.1 是 k8s 的服务 ip,千万不要和现有的网络一致,避免出现冲突 这个大家根据自己的实际场景来决定是否修改,如果有修改的,后面涉及到的 ip 都要记得修改 同样的,在配置 ip 的时候,注意 json
格式的 , 逗号位置

cat << EOF > ${work_dir}/tmp/ssl/apiserver-csr.json
{
  "CN": "kubernetes",
  "hosts": [
    "127.0.0.1",
    "192.168.11.147",
    "192.168.11.148",
    "192.168.11.149",
    "10.88.0.1",
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShangHai",
      "L": "ShangHai",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

创建 apiserver 证书

${work_dir}/bin/cfssl gencert \
-ca=${work_dir}/tmp/ssl/ca.pem \
-ca-key=${work_dir}/tmp/ssl/ca-key.pem \
-config=${work_dir}/tmp/ssl/ca-config.json \
-profile=kubernetes ${work_dir}/tmp/ssl/apiserver-csr.json | \
${work_dir}/bin/cfssljson -bare ${work_dir}/tmp/ssl/apiserver

配置 metrics-server 证书

这个看各自的需求是否要部署 metrics-server 服务 没有 metrics-server 只是影响 dashboard
的图形化不展示 没有 metrics-server 就玩不了 kubernetes 的 hpa 功能

cat << EOF > ${work_dir}/tmp/ssl/aggregator-csr.json
{
  "CN": "aggregator",
  "hosts": [
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShangHai",
      "L": "ShangHai",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

创建 metrics-server 证书

${work_dir}/bin/cfssl gencert \
-ca=${work_dir}/tmp/ssl/ca.pem \
-ca-key=${work_dir}/tmp/ssl/ca-key.pem \
-config=${work_dir}/tmp/ssl/ca-config.json \
-profile=kubernetes ${work_dir}/tmp/ssl/aggregator-csr.json | \
${work_dir}/bin/cfssljson -bare ${work_dir}/tmp/ssl/aggregator

配置 apiserver 为 systemctl 管理

下面的 ip 记得替换成自己的节点 ip

–service-cluster-ip-range 参数的 ip 网段要和 apiserver-csr.json 里面的 10.88.0.1 是一个网段的
–etcd-servers 写上所有的 etcd 节点 如果不考虑部署 metrics-server 服务,以下七个参数需要去掉
–requestheader-client-ca-file
–requestheader-allowed-names
–requestheader-extra-headers-prefix
–requestheader-group-headers
–requestheader-username-headers
–proxy-client-cert-file
–proxy-client-key-file apiserver 参数

创建 systemctl 启动模板

cat << EOF > ${work_dir}/tmp/service/kube-apiserver.service.template
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
ExecStart=##k8sBin##/kube-apiserver \\
  --secure-port=6443 \\
  --allow-privileged=true \\
  --anonymous-auth=false \\
  --api-audiences=api,istio-ca \\
  --authorization-mode=Node,RBAC \\
  --bind-address=##k8sHost## \\
  --client-ca-file=##sslPath##/ca.pem \\
  --endpoint-reconciler-type=lease \\
  --etcd-cafile=##sslPath##/ca.pem \\
  --etcd-certfile=##sslPath##/apiserver.pem \\
  --etcd-keyfile=##sslPath##/apiserver-key.pem \\
  --etcd-servers=##etcdEndpoints## \\
  --kubelet-certificate-authority=##sslPath##/ca.pem \\
  --kubelet-client-certificate=##sslPath##/apiserver.pem \\
  --kubelet-client-key=##sslPath##/apiserver-key.pem \\
  --service-account-issuer=https://kubernetes.default.svc \\
  --service-account-signing-key-file=##sslPath##/ca-key.pem \\
  --service-account-key-file=##sslPath##/ca.pem \\
  --service-cluster-ip-range=10.88.0.0/16 \\
  --service-node-port-range=30000-32767 \\
  --tls-cert-file=##sslPath##/apiserver.pem \\
  --tls-private-key-file=##sslPath##/apiserver-key.pem \\
  --requestheader-client-ca-file=##sslPath##/ca.pem \\
  --requestheader-allowed-names= \\
  --requestheader-extra-headers-prefix=X-Remote-Extra- \\
  --requestheader-group-headers=X-Remote-Group \\
  --requestheader-username-headers=X-Remote-User \\
  --proxy-client-cert-file=##sslPath##/aggregator.pem \\
  --proxy-client-key-file=##sslPath##/aggregator-key.pem \\
  --enable-aggregator-routing=true \\
  --v=2
Restart=always
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

完成

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐