本文将针对k8s每个组件,逐一部署,了解每个组件所需要的文件以及配置,在部署上更清晰易懂。更方便于日后问题排查。
介绍:Kubernetes(简称为:k8s)是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了资源调度、部署管理、服务发现、扩容缩容、监控,维护等一整套功能,努力成为跨主机集群的自动部署、扩展以及运行应用程序容器的平台。 它支持一系列容器工具, 包括Docker、Containerd等。
版本说明:https://kubernetes.io/zh-cn/releases/
集群为2主1从
hostname | ip | 软件 |
---|---|---|
master1 | 192.168.1.21 | cfssl,containerd,etcd,kube-apiserver,kube-controller-manager,kube-schedule,kubelet,kube-proxy,nginx,keepalived |
master2 | 192.168.1.22 | containerd,etcd,kube-apiserver,kube-controller-manager,kube-schedule,kubelet,kube-proxy,nginx,keepalived |
node1 | 192.168.1.23 | containerd,kubelet,kube-proxy |
docker-registry | 192.168.1.9 | docker |
说明: 在部署服务中,镜像官网都是国外网站,如果网络不好有波动,会出现镜像拉取失败的报错,docker-registry上部署镜像仓库,主要为集群提供镜像,上面的镜像都是根据官网yaml文件提前拉取好的镜像。方便集群的快速部署。
软件 | 版本 |
---|---|
kernel | v6.3.3-1.el7 |
CentOs | v7.9.2009 |
containerd | v1.7.1 |
runc | v1.1.4 |
cfssl | v1.6.3 |
etcd | v3.5.8 |
nginx | 1.23.3 |
keepalived | yum源默认 |
kube-apiserver,kube-controller-manager,kube-schedule,kubelet,kube-proxy | v1.27.1 |
docker | 24.0.1 |
calico | v3.25 |
coredns | v1.9.4 |
dashboard | v2.5.0 |
集群安装时会涉及到三个网段:
宿主机网段:就是安装k8s的服务器
Pod网段:k8s Pod的网段,相当于容器的IP
Service网段:k8s service网段,service用于集群容器通信。
vip: apiserver高可用地址
网络名称 | 网段 |
---|---|
Node网络 | 192.168.1.0/24 |
Service网络 | 10.96.0.0/16 |
Pod网络 | 10.244.0.0/16 |
vip(虚拟ip) | 192.168.1.25 |
hostnamectl set-hostname master1
nmcli connection modify ens33 ipv4.method manual ipv4.addresses "192.168.1.21/24" ipv4.gateway 192.168.1.254 ipv4.dns "8.8.8.8,114.114.114.114" connection.autoconnect yes
nmcli connection up ens33
hostnamectl set-hostname master2
nmcli connection modify ens33 ipv4.method manual ipv4.addresses "192.168.1.22/24" ipv4.gateway 192.168.1.254 ipv4.dns "8.8.8.8,114.114.114.114" connection.autoconnect yes
nmcli connection up ens33
hostnamectl set-hostname node1
nmcli connection modify ens33 ipv4.method manual ipv4.addresses "192.168.1.23/24" ipv4.gateway 192.168.1.254 ipv4.dns "8.8.8.8,114.114.114.114" connection.autoconnect yes
nmcli connection up ens33
hostnamectl set-hostname docker-registry
nmcli connection modify ens33 ipv4.method manual ipv4.addresses "192.168.1.9/24" ipv4.gateway 192.168.1.254 ipv4.dns "8.8.8.8,114.114.114.114" connection.autoconnect yes
nmcli connection up ens33
说明
网关需要和自己VMware配置的对应,配置dns为了方便访问互联网
ping baidu.com
PING baidu.com (39.156.66.10) 56(84) bytes of data.
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=1 ttl=128 time=213 ms
64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=2 ttl=128 time=109 ms
[root@master1 ~]# cat >> /etc/hosts << 'EOF'
192.168.1.21 master1
192.168.1.22 master2
192.168.1.23 node1
EOF
[root@master1 ~]# for i in {22,23}
do
scp /etc/hosts 192.168.1.$i:/etc/hosts
done
#配置master1可以免密登录其他主机,大部分操作都在master1,部署完成后将其他节点需要的文件scp过去
[root@master1 ~]# ssh-keygen -t rsa -P '' -f /root/.ssh/id_rsa
[root@master1 ~]# for i in {master1,master2,node1}
do
ssh-copy-id $i
done
#使用本地镜像包挂载
cat >> /etc/fstab << 'EOF'
/media/CentOS-7-x86_64-Everything-2009.iso /mnt iso9660 defaults 0 0
EOF
#让配置生效
mount -a
#编写yum配置文件
cd /etc/yum.repos.d/
mkdir bak
mv * bak/
cat > local.repo << 'EOF'
[dvd]
name=dvd
baseurl=file:///mnt
enabled=1
gpgcheck=0
EOF
#查看yum软件包
yum clean all
yum repolist
或者配置国内的阿里云在线镜像 (官网有配置方法) https://developer.aliyun.com/mirror/
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
#非阿里云ECS用户会出现 Couldn't resolve host 'mirrors.cloud.aliyuncs.com' 信息,不影响使用。用户也可自行修改相关配置: eg:
sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo
[root@master1 ~]# for i in {22,23}
do
scp -r /etc/yum.repos.d/ 192.168.1.$i:/etc/
done
yum -y install wget net-tools telnet curl
[root@master1 ~]# for i in {master1,master2,node1}
do
ssh $i "systemctl disable --now firewalld"
done
[root@master1 ~]# for i in {master1,master2,node1}
do
ssh $i "setenforce 0;sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config"
done
[root@master1 ~]# for i in {master1,master2,node1}
do
ssh $i "sed -i 's/.*swap.*/#&/' /etc/fstab;swapoff -a ;sysctl -w vm.swappiness=0"
done
说明: sysctl -w vm.swappiness=0 是用来设置Linux系统的虚拟内存使用策略的。其中,vm.swappiness是一个内核参数,它控制了系统在物理内存不足时,会把哪些数据交换到磁盘上的swap分区中。这个参数的值越大,系统就越倾向于使用swap分区,反之则越少。将vm.swappiness设置为0,就是告诉系统在物理内存不足时不要使用swap分区,而是直接杀掉进程。
#配置 NetworkManager 服务,以允许 Calico 管理网络接口
[root@master1 ~]# cat > /etc/NetworkManager/conf.d/calico.conf << EOF
[keyfile]
unmanaged-devices=interface-name:cali*;interface-name:tunl*
EOF
文件说明:
指定 NetworkManager 不应管理任何名称以 cali 或 tunl 开头的网络接口。这些接口由 Calico 用于在 Kubernetes 集群中进行网络和策略执行。默认情况下,NetworkManager 可能会干扰这些接口的操作,导致集群中的网络和策略执行出现问题。通过配置 NetworkManager 忽略这些接口,您可以确保 Calico 能够在您的 Kubernetes 集群中正确运行。
[root@master1 ~]# for i in {master1,master2,node1}
do
scp /etc/NetworkManager/conf.d/calico.conf $i:/etc/NetworkManager/conf.d/calico.conf
ssh $i "systemctl restart NetworkManager"
done
#修改ssh配置文件
[root@master1 ~]# vim /etc/ssh/sshd_config
UseDNS no
GSSAPIAuthentication no
[root@master1 ~]# systemctl restart sshd
[root@master1 ~]# for i in {master2,node1}
do
scp /etc/ssh/sshd_config $i:/etc/ssh/sshd_config
ssh $i "systemctl restart sshd"
done
#上面内容整理为一条命令
[root@master1 ~]# for i in {master1,master2,node1}
do
ssh $i "sed -i 's/#UseDNS\ yes/UseDNS\ no/g; s/GSSAPIAuthentication\ yes/GSSAPIAuthentication\ no/g' /etc/ssh/sshd_config"
ssh $i "systemctl restart sshd"
done
#推荐使用chrony配置
[root@master1 ~]# for i in {master1,master2,node1}
do
ssh $i "yum -y install chrony && sed -i -e '/^server.*/d' -e '/^# Please consider .*/a\server\ ntp.aliyun.com\ iburst' /etc/chrony.conf;systemctl restart chronyd"
done
#验证
[root@master1 ~]# chronyc sources -v
210 Number of sources = 1
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* 203.107.6.88 2 6 17 3 -28us[ +681us] +/- 32ms
#临时修改文件描述符的限制
ulimit -SHn 65535
[root@master1 ~]# cat >>/etc/security/limits.conf << 'EOF'
* soft nofile 65536
* hard nofile 131072
* soft nproc 65536
* hard nproc 655350
* soft memlock unlimited
* hard memlock unlimited
EOF
#limit优化
[root@master1 ~]# for i in {master1,master2,node1}
do
scp /etc/security/limits.conf $i:/etc/security/limits.conf
ssh $i "ulimit -SHn 65535;sysctl --system"
done
#3.10的kernel问题太多,也是k8s支持的最低版本,CentOS7需要升级内核才可以稳定运行kubernetes各组件,其它系统根据自己的需求去升级。
#下载内核安装包
地址:https://elrepo.org/linux/kernel/el7/x86_64/RPMS/ #lt长期维护版 ml最新稳定版
[root@master1 ~]# mkdir kernel
[root@master1 ~]# cd kernel/
[root@master1 kernel]# wget https://elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-ml-6.3.3-1.el7.elrepo.x86_64.rpm
[root@master1 kernel]# wget https://elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-ml-devel-6.3.3-1.el7.elrepo.x86_64.rpm
#安装并配置默认内核,然后重启,安装时间较长,耐心等待,安装中不要操作
[root@master1 kernel]# yum -y install kernel-ml-6.3.3-1.el7.elrepo.x86_64.rpm kernel-ml-devel-6.3.3-1.el7.elrepo.x86_64.rpm
[root@master1 kernel]# grubby --set-default $(ls /boot/vmlinuz-* | grep elrepo) && reboot
#其他节点安装
[root@master1 kernel]# for i in {master2,node1}
do
scp -r /root/kernel $i:/root/
ssh $i "cd /root/kernel;yum -y install kernel-ml-6.3.3-1.el7.elrepo.x86_64.rpm kernel-ml-devel-6.3.3-1.el7.elrepo.x86_64.rpm"
ssh $i "grubby --set-default $(ls /boot/vmlinuz-* | grep elrepo) && reboot"
done
#验证
[root@master1 ~]# for i in {master2,node1}
do
ssh $i "echo $i 的内核版本是 `uname -r`"
done
master1 的内核版本是 6.3.3-1.el7.elrepo.x86_64
master2 的内核版本是 6.3.3-1.el7.elrepo.x86_64
node1 的内核版本是 6.3.3-1.el7.elrepo.x86_64
[root@master1 ~]# cat > /etc/sysctl.d/k8s.conf << 'EOF'
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
fs.may_detach_mounts = 1
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.netfilter.nf_conntrack_max=2310720
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =15
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 327680
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.ip_conntrack_max = 65536
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 0
net.core.somaxconn = 16384
EOF
#分发给其他节点并加载配置
[root@master1 ~]# for i in {master1,master2,node1}
do
scp /etc/sysctl.d/k8s.conf $i:/etc/sysctl.d/k8s.conf
ssh $i "sysctl --system"
done
[root@master1 ~]# yum -y install ipvsadm ipset sysstat conntrack libseccomp
[root@master1 ~]# cat >> /etc/modules-load.d/ipvs.conf <
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
ip_tables
ip_set
xt_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
EOF
[root@master1 ~]# systemctl restart systemd-modules-load.service
[root@master1 ~]# for i in {master2,node1}
do
ssh $i "yum -y install ipvsadm ipset sysstat conntrack libseccomp && systemctl restart systemd-modules-load.service"
done
kubernetes v1.24 版本以上推荐 Containerd
ctr是containerd本身的CLI工具。
crictl是kubernetes社区定义的专门CLI工具。
Kubernetes1.24的时候已经不在依附于docker,当时的容器技术也不仅仅只有docker可选,还有其它的容器可选,因此它就终于独立了,它决定把dockershim这个组件不再开发把它移除,这时候就变成了什么样子了,dockershim就彻底的没有了,1.24把dockershim抛弃了,docker就没办法通过CRI和k8s进行通讯,自然k8s也就没有办法来使用docker的容器技术,当然docker也没有办法通过k8s来进行结合使用,这个对于k8s来讲已经不是问题,因为k8s除了docker以外它还有其它的容器技术可选,而docker对应的企业级的编排的领域只有k8s可选,因为k8s已经是垄断地位它没有第三方可选,在这种情况下docker放低身段只好自己开发一个软件贴在CRI基础之上这就是cri-dockerd,cri-dockerd是docker公司开发出来的,人家不兼容了抛弃你了,那我就自己做个软件叫cri-dockerd来遵守CRI从而才能和k8s组合在一起。
[root@master1 ~]# wget https://github.com/containerd/containerd/releases/download/v1.7.1/cri-containerd-cni-1.7.1-linux-amd64.tar.gz
#解压cri-containerd-cni安装包
#查看tar包文件目录结构
[root@master1 ~]# tar -tvf cri-containerd-cni-1.7.1-linux-amd64.tar.gz
#默认解压后会有如下目录:etc、opt、usr 把对应的目解压到 / 下对应目录中,这样就省去复制文件步骤
[root@master1 ~]# tar -xf cri-containerd-cni-1.7.1-linux-amd64.tar.gz -C /
#查看containerd 服务启动文件,无需修改
[root@master1 ~]# grep -v '^$\|^\s*#' /etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=infinity
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
[root@master1 ~]# cat > /etc/modules-load.d/containerd.conf << EOF
overlay
br_netfilter
EOF
#加载模块
[root@master1 ~]# systemctl restart systemd-modules-load.service
#查看containerd相关模块加载情况:
[root@master1 ~]# lsmod | egrep 'br_netfilter|overlay'
[root@master1 ~]# cat > /etc/sysctl.d/99-kubernetes-cri.conf << 'EOF'
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
#加载内核
[root@master1 ~]# sysctl --system
#创建默认配置文件
[root@master1 ~]# mkdir /etc/containerd
[root@master1 ~]# containerd config default > /etc/containerd/config.toml
[root@master1 ~]# grep SystemdCgroup /etc/containerd/config.toml
SystemdCgroup = false #修改为true
[root@master1 ~]# sed -i s#SystemdCgroup\ =\ false#SystemdCgroup\ =\ true# /etc/containerd/config.toml
#配置镜像地址
[root@master1 ~]# grep registry.k8s.io /etc/containerd/config.toml
sandbox_image = "registry.k8s.io/pause:3.8"
[root@master1 ~]# sed -i s#registry.k8s.io#registry.aliyuncs.com/google_containers# /etc/containerd/config.toml
#配置私有仓库,如果配置harbor请参考我的文章:使用 cfssl 工具生成证书离线部署Harbor企业级私有镜像仓库
[root@master1 ~]# vim /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.1.9:5000"]
endpoint = ["http://192.168.1.9:5000"]
#说明:在 [plugins."io.containerd.grpc.v1.cri".registry.mirrors] 下面添加2行内容,因为后面在部署calico等组件时,我们会拉取私有仓库上已经push好的官网镜像。实现快速安装。crictl拉取私有docker-registry仓库镜像需要此配置,不然会报错。如果网络没问题,可以实现科学上网,在后面部署中可以直接部署。可不用修改此配置。
[root@master1 ~]# systemctl daemon-reload
[root@master1 ~]# systemctl enable --now containerd
[root@master1 ~]# systemctl status containerd
crictl客户端连接的运行时位置配置作用是指定crictl客户端连接的容器运行时的位置。这个位置通常是一个Unix套接字文件,它允许crictl与容器运行时进行通信,以便管理容器和镜像。如果您想使用crictl管理Docker容器,您需要将crictl配置为连接到Docker的Unix套接字文件。例如,您可以在/etc/crictl.yaml中设置runtime-endpoint和image-endpoint参数来指定containerd的Unix套接字文件路径
#修改crictl配置文件
[root@master1 ~]# cat > /etc/crictl.yaml <
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
[root@master1 ~]# systemctl restart containerd
containerd 常用命令crictl
#查看
[root@master1 ~]# crictl info
[root@master1 ~]# crictl ps
#crictl常用命令:
#拉取镜像
crictl pull <image_name>
#上传镜像
crictl push <image_name> <registry>
#crictl推送镜像
crictl push <image_name> <registry>
#保存镜像为tar包
crictl image export <image_name.tar> <image_name:tag>
#给镜像打标签
crictl image tag <image_new_name> <image_name>
#重命名镜像
crictl image rename <new_name> <image_name>
#加载本地镜像包
crictk load <image.tar>
#运行pod
crictl runp <pod_name>
#查看pod
crictl ps
#查看容器
crictl ps -a
#查看镜像
crictl images
#删除容器:
crictl rm <container_id>
#删除镜像
crictl rmi <image_id>
#创建pod
crictl runp <pod_name> --port-mappings=<container_port:host_port> --mount=type=bind,src=<host_dir_path>,dst=<container_dir_path> <image_name>
由于上述软件包中包含的runc对系统依赖过多,所以建议单独下载安装。
默认runc执行时提示:runc: symbol lookup error: runc: undefined symbol: seccomp_notify_respond
[root@master1 ~]# runc
runc: symbol lookup error: runc: undefined symbol: seccomp_notify_respond
#下载runc安装包
[root@master1 ~]# wget https://github.com/opencontainers/runc/releases/download/v1.1.4/runc.amd64
#替换掉原软件包中的runc
[root@master1 ~]# whereis runc
[root@master1 ~]# mv -f runc.amd64 /usr/local/sbin/runc
[root@master1 ~]# chmod +x /usr/local/sbin/runc
[root@master1 ~]# runc -v
runc version 1.1.4
commit: v1.1.4-0-g5fd4c4d1
spec: 1.0.2-dev
go: go1.17.10
libseccomp: 2.5.4
#重启containerd
[root@master1 ~]# systemctl restart containerd
[root@master1 ~]# for i in {master2,node1}
do
scp cri-containerd-cni-1.7.1-linux-amd64.tar.gz $i:/root/
ssh $i "tar -xf cri-containerd-cni-1.7.1-linux-amd64.tar.gz -C /"
scp /etc/modules-load.d/containerd.conf $i:/etc/modules-load.d/containerd.conf
scp /etc/sysctl.d/99-kubernetes-cri.conf $i:/etc/sysctl.d/99-kubernetes-cri.conf
scp -r /etc/containerd/ $i:/etc/
scp -p /usr/local/sbin/runc $i:/usr/local/sbin/runc
ssh $i "systemctl enable --now containerd"
done
Etcd 是一个分布式键值存储系统,Kubernetes使用Etcd进行数据存储,所以先准备一个Etcd数据库,为解决Etcd单点故障,应采用集群方式部署,这里使用3台组建集群,可容忍1台机器故障,当然,你也可以使用5台组建集群,可容忍2台机器故障
为了节省机器,这里与k8s节点复用,也可以部署在k8s机器之外,只要apiserver能连接到就行。
#cfssl是使用go编写,由CloudFlare开源的一款PKI/TLS工具。主要程序有:
- cfssl,是CFSSL的命令行工具。
- cfssljson用来从cfssl程序获取JSON输出,并将证书,密钥,CSR和bundle写入文件中。
[root@master1 ~]# wget "https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssl_1.6.3_linux_amd64" -O /usr/local/bin/cfssl
[root@master1 ~]# wget "https://github.com/cloudflare/cfssl/releases/download/v1.6.3/cfssljson_1.6.3_linux_amd64" -O /usr/local/bin/cfssljson
[root@master1 ~]# chmod +x /usr/local/bin/cfssl*
[root@master1 ~]# cfssl version
Version: 1.6.3
Runtime: go1.18
各种 CA 证书类型:
https://github.com/kubernetes-incubator/apiserver-builder/blob/master/docs/concepts/auth.md
#创建自签工作目录
[root@master1 ~]# mkdir -p ~/pki/{etcd,k8s}
[root@master1 ~]# cd ~/pki/etcd/
# cfssl print-defaults csr > ca-csr.json 可生成模板
#配置ca请求证书
[root@master1 etcd]# cat > etcd-ca-csr.json << EOF
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "etcd",
"OU": "Etcd Security"
}
],
"ca": {
"expiry": "876000h"
}
}
EOF
**ca-csr.json文件中包含如下内容简要说明:**
"CN": "etcd":这将证书的通用名称 (CN) 设置为 “etcd”。
"key": {"algo": "rsa", "size": 2048}:这指定了密钥算法应该使用 RSA,密钥大小为 2048 位。
"names": [{"C": "CN", "ST": "Beijing", "L": "Beijing", "O": "etcd", "OU": "Etcd Security"}]:这设置了证书的主题信息。字段如下:
"C": "CN":这将国家名称设置为 CN (中国)。
"ST": "Beijing":这将州或省名称设置为北京。
"L": "Beijing":这将地区名称设置为北京。
"O": "etcd":这将组织名称设置为 etcd。
"OU": "Etcd Security":这将组织单位名称设置为 Etcd Security。
"ca": {"expiry": "876000h"}:这将 CA 证书的过期时间设置为 876000 小时,相当于 100 年。
#创建证书存放目录
[root@master1 etcd]# mkdir -p /opt/etcd/{ssl,bin,cfg}
[root@master1 etcd]# cfssl gencert -initca etcd-ca-csr.json | cfssljson -bare /opt/etcd/ssl/etcd-ca
#cfssl print-defaults config > ca-config.json 此命令可生成模板文件,可在基础上修改
[root@master1 etcd]# cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "876000h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "876000h"
}
}
}
}
EOF
"signing":此字段包含 CA 的签名过程的配置。
"default":此字段包含签名过程的默认配置。
"expiry": "876000h":将 CA 颁发的证书的默认过期时间设置为 876000 小时,相当于 100 年。
"profiles":此字段包含不同签名配置文件的配置。
"kubernetes":这是一个名为 “kubernetes” 的自定义配置文件。
"usages": ["signing", "key encipherment", "server auth", "client auth"]:设置使用此配置文件颁发的证书的允许用途。允许的用途包括签名、密钥加密、服务器身份验证和客户端身份验证。
"expiry": "876000h":将使用此配置文件颁发的证书的过期时间设置为 876000 小时,相当于 100 年
[root@master1 etcd]# cat > etcd-csr.json << EOF
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "etcd",
"OU": "Etcd Security"
}
]
}
EOF
[root@master1 etcd]# cfssl gencert \
-ca=/opt/etcd/ssl/etcd-ca.pem \
-ca-key=/opt/etcd/ssl/etcd-ca-key.pem \
-config=ca-config.json \
-hostname=127.0.0.1,192.168.1.21,192.168.1.22,192.168.1.23 \
-profile=kubernetes \
etcd-csr.json | cfssljson -bare /opt/etcd/ssl/etcd
上述命令hostname中ip为所有etcd节点的集群内部通信ip,一个都不能少,为了方便后期扩容可以多写几个预留的ip。
#下载安装包
[root@master1 ~]# https://github.com/etcd-io/etcd/releases/download/v3.5.8/etcd-v3.5.8-linux-amd64.tar.gz
#解压etcd安装包
[root@master1 ~]# tar -xf etcd-v3.5.8-linux-amd64.tar.gz
[root@master1 ~]# cd etcd-v3.5.8-linux-amd64/
[root@master1 etcd-v3.5.8-linux-amd64]# cp -p etcd etcdctl /opt/etcd/bin/
#查看
[root@master1 ~]# /opt/etcd/bin/etcdctl version
etcdctl version: 3.5.8
API version: 3.5
[root@master1 ~]# cat > /opt/etcd/cfg/etcd.config.yml << EOF
name: 'master1'
data-dir: /var/lib/etcd
wal-dir: /var/lib/etcd/wal
snapshot-count: 5000
heartbeat-interval: 100
election-timeout: 1000
quota-backend-bytes: 0
listen-peer-urls: 'https://192.168.1.21:2380'
listen-client-urls: 'https://192.168.1.21:2379,http://127.0.0.1:2379'
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: 'https://192.168.1.21:2380'
advertise-client-urls: 'https://192.168.1.21:2379'
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: 'master1=https://192.168.1.21:2380,master2=https://192.168.1.22:2380,node1=https://192.168.1.23:2380'
initial-cluster-token: 'etcd-k8s-cluster'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
client-transport-security:
cert-file: '/opt/etcd/ssl/etcd.pem'
key-file: '/opt/etcd/ssl/etcd-key.pem'
client-cert-auth: true
trusted-ca-file: '/opt/etcd/ssl/etcd-ca.pem'
auto-tls: true
peer-transport-security:
cert-file: '/opt/etcd/ssl/etcd.pem'
key-file: '/opt/etcd/ssl/etcd-key.pem'
peer-client-cert-auth: true
trusted-ca-file: '/opt/etcd/ssl/etcd-ca.pem'
auto-tls: true
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
EOF
[root@master1 ~]# cat > /usr/lib/systemd/system/etcd.service << EOF
[Unit]
Description=Etcd Service
Documentation=https://coreos.com/etcd/docs/latest/
After=network.target
[Service]
Type=notify
ExecStart=/opt/etcd/bin/etcd --config-file=/opt/etcd/cfg/etcd.config.yml
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Alias=etcd3.service
EOF
[root@master1 ~]# for i in {master2,node1}
do
scp -r /opt/etcd/ $i:/opt/
scp /usr/lib/systemd/system/etcd.service $i:/usr/lib/systemd/system/etcd.service
done
[root@master2 ~]# cat > /opt/etcd/cfg/etcd.config.yml << EOF
name: 'master2'
data-dir: /var/lib/etcd
wal-dir: /var/lib/etcd/wal
snapshot-count: 5000
heartbeat-interval: 100
election-timeout: 1000
quota-backend-bytes: 0
listen-peer-urls: 'https://192.168.1.22:2380'
listen-client-urls: 'https://192.168.1.22:2379,http://127.0.0.1:2379'
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: 'https://192.168.1.22:2380'
advertise-client-urls: 'https://192.168.1.22:2379'
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: 'master1=https://192.168.1.21:2380,master2=https://192.168.1.22:2380,node1=https://192.168.1.23:2380'
initial-cluster-token: 'etcd-k8s-cluster'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
client-transport-security:
cert-file: '/opt/etcd/ssl/etcd.pem'
key-file: '/opt/etcd/ssl/etcd-key.pem'
client-cert-auth: true
trusted-ca-file: '/opt/etcd/ssl/etcd-ca.pem'
auto-tls: true
peer-transport-security:
cert-file: '/opt/etcd/ssl/etcd.pem'
key-file: '/opt/etcd/ssl/etcd-key.pem'
peer-client-cert-auth: true
trusted-ca-file: '/opt/etcd/ssl/etcd-ca.pem'
auto-tls: true
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
EOF
[root@node1 ~]# cat > /opt/etcd/cfg/etcd.config.yml << EOF
name: 'node1'
data-dir: /var/lib/etcd
wal-dir: /var/lib/etcd/wal
snapshot-count: 5000
heartbeat-interval: 100
election-timeout: 1000
quota-backend-bytes: 0
listen-peer-urls: 'https://192.168.1.23:2380'
listen-client-urls: 'https://192.168.1.23:2379,http://127.0.0.1:2379'
max-snapshots: 3
max-wals: 5
cors:
initial-advertise-peer-urls: 'https://192.168.1.23:2380'
advertise-client-urls: 'https://192.168.1.23:2379'
discovery:
discovery-fallback: 'proxy'
discovery-proxy:
discovery-srv:
initial-cluster: 'master1=https://192.168.1.21:2380,master2=https://192.168.1.22:2380,node1=https://192.168.1.23:2380'
initial-cluster-token: 'etcd-k8s-cluster'
initial-cluster-state: 'new'
strict-reconfig-check: false
enable-v2: true
enable-pprof: true
proxy: 'off'
proxy-failure-wait: 5000
proxy-refresh-interval: 30000
proxy-dial-timeout: 1000
proxy-write-timeout: 5000
proxy-read-timeout: 0
client-transport-security:
cert-file: '/opt/etcd/ssl/etcd.pem'
key-file: '/opt/etcd/ssl/etcd-key.pem'
client-cert-auth: true
trusted-ca-file: '/opt/etcd/ssl/etcd-ca.pem'
auto-tls: true
peer-transport-security:
cert-file: '/opt/etcd/ssl/etcd.pem'
key-file: '/opt/etcd/ssl/etcd-key.pem'
peer-client-cert-auth: true
trusted-ca-file: '/opt/etcd/ssl/etcd-ca.pem'
auto-tls: true
debug: false
log-package-levels:
log-outputs: [default]
force-new-cluster: false
EOF
#三个节点同时启动
systemctl daemon-reload
systemctl enable --now etcd
systemctl status etcd
# 检查ETCD数据库集群状态:
[root@master1 ~]# ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/etcd-ca.pem --cert=/opt/etcd/ssl/etcd.pem --key=/opt/etcd/ssl/etcd-key.pem --endpoints="https://192.168.1.21:2379,https://192.168.1.22:2379,https://192.168.1.23:2379" endpoint health --write-out=table
+---------------------------+--------+------------+-------+
| ENDPOINT | HEALTH | TOOK | ERROR |
+---------------------------+--------+------------+-------+
| https://192.168.1.21:2379 | true | 7.471012ms | |
| https://192.168.1.22:2379 | true | 8.072207ms | |
| https://192.168.1.23:2379 | true | 8.248099ms | |
+---------------------------+--------+------------+-------+
# 检查ETCD数据库性能:
[root@master1 ~]# ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/etcd-ca.pem --cert=/opt/etcd/ssl/etcd.pem --key=/opt/etcd/ssl/etcd-key.pem --endpoints="https://192.168.1.21:2379,https://192.168.1.22:2379,https://192.168.1.23:2379" check perf --write-out=table
59 / 60 59 / 60 Boooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooom ! 98.33%
PASS: Throughput is 150 writes/sPASS: Slowest request took 0.048788s
PASS: Stddev is 0.001209s
PASS
# 检查ETCD数据库集群
[root@master1 ~]# ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/etcd-ca.pem --cert=/opt/etcd/ssl/etcd.pem --key=/opt/etcd/ssl/etcd-key.pem --endpoints="https://192.168.1.21:2379,https://192.168.1.22:2379,https://192.168.1.23:2379" member list --write-out=table
+------------------+---------+--------+---------------------------+---------------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+--------+---------------------------+---------------------------+------------+
| 22cb69b2fd1bb417 | started | etcd-1 | https://192.168.1.21:2380 | https://192.168.1.21:2379 | false |
| 3c3bd4fd7d7e553e | started | etcd-2 | https://192.168.1.22:2380 | https://192.168.1.22:2379 | false |
| 86ab7347ef3517f6 | started | etcd-3 | https://192.168.1.23:2380 | https://192.168.1.23:2379 | false |
+------------------+---------+--------+---------------------------+---------------------------+------------+
# 检查ETCD数据库集群认证:
[root@master1 ~]# ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/etcd-ca.pem --cert=/opt/etcd/ssl/etcd.pem --key=/opt/etcd/ssl/etcd-key.pem --endpoints="https://192.168.1.21:2379,https://192.168.1.22:2379,https://192.168.1.23:2379" endpoint status --write-out=table
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.1.21:2379 | 22cb69b2fd1bb417 | 3.5.8 | 35 MB | true | false | 2 | 15225 | 15225 | |
| https://192.168.1.22:2379 | 3c3bd4fd7d7e553e | 3.5.8 | 35 MB | false | false | 2 | 15226 | 15226 | |
| https://192.168.1.23:2379 | 86ab7347ef3517f6 | 3.5.8 | 35 MB | false | false | 2 | 15227 | 15227 | |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
Nginx是一个主流Web服务和反向代理服务器,这里用四层实现对apiserver实现负载均衡。
Keepalived是一个主流高可用软件,基于VIP绑定实现服务器双机热备,Keepalived主要根据Nginx运行状态判断是否需要故障转移(漂移VIP),例如当Nginx主节点挂掉,VIP会自动绑定在Nginx备节点,从而保证VIP一直可用,实现Nginx高可用。
如果你是在公有云上,一般都不支持keepalived,那么你可以直接用它们的负载均衡器产品,直接负载均衡多台Master kube-apiserver。
在master1和master2上操作
[root@master1 ~]# wget http://nginx.org/download/nginx-1.23.3.tar.gz
#安装依赖包
[root@master1 ~]# yum -y install gcc gcc-c++ make pcre pcre-devel zlib zlib-devel openssl openssl-devel
[root@master1 ~]# tar -xf nginx-1.23.3.tar.gz
#编译安装
[root@master1 ~]# cd nginx-1.23.3/
[root@master1 nginx-1.23.3]# ./configure --prefix=/usr/local/nginx --with-stream --without-http --without-http_uwsgi_module --without-http_scgi_module --without-http_fastcgi_module
[root@master1 nginx-1.23.3]# make && make install
--prefix=PATH:指定安装目录。
--with-xxx:指定编译选项,例如 --with-openssl 指定使用 OpenSSL 库。
--without-xxx:禁用某个模块,例如 --without-http_rewrite_module 禁用 HTTP Rewrite 模块。
--enable-xxx:启用某个模块,例如 --enable-debug 启用调试模式。
--disable-xxx:禁用某个模块,例如 --disable-shared 禁用共享库。
更多参数可以通过运行 ./configure --help 查看
[root@master1 nginx-1.23.3]# cd /usr/local/nginx/conf/
[root@master1 conf]# grep -Ev "^#|^$" nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
stream {
log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
access_log /usr/local/nginx/logs/k8s-access.log main;
upstream k8s-apiserver {
server 192.168.1.21:6443 max_fails=3 fail_timeout=30s;
server 192.168.1.22:6443 max_fails=3 fail_timeout=30s;
}
server {
listen 16443;
proxy_connect_timeout 1s;
proxy_pass k8s-apiserver;
}
}
#添加 stream 模块的信息,删除http模块(编译的时候 --without-http),其余的不用修改即可
#在 Nginx 配置文件中,log_format 指令用于定义日志格式。main 是自定义的日志格式名称,$remote_addr、$upstream_addr、$time_local、$status 和 $upstream_bytes_sent 是日志格式的变量。其中,$remote_addr 表示客户端 IP 地址,$upstream_addr 表示后端服务器 IP 地址,$time_local 表示访问时间,$status 表示 HTTP 状态码,$upstream_bytes_sent 表示响应大小
[root@master1 conf]# cat > /usr/lib/systemd/system/nginx.service << 'EOF'
[Unit]
Description=nginx - high performance web server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
[root@master1 ~]# scp -r /usr/local/nginx/ master2:/usr/local/
[root@master1 ~]# scp /usr/lib/systemd/system/nginx.service master2:/usr/lib/systemd/system/
[root@master1 ~]# yum -y install keepalived.x86_64
[root@master1 ~]# grep -Ev "^#|^$" /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
interval 5
weight -5
fall 2
rise 1
}
vrrp_instance VI_1 {
state MASTER
interface ens33
mcast_src_ip 192.168.1.21
virtual_router_id 51
priority 100
nopreempt
advert_int 2
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.25
}
track_script {
check_apiserver
}
}
# priority 100 # 优先级,备服务器设置 90 小于主服务器即可
# advert_int 1 # 指定VRRP 心跳包通告间隔时间,默认1秒
vrrp_script:指定检查nginx工作状态脚本(根据nginx状态判断是否故障转移)
virtual_ipaddress:虚拟IP(VIP)
[root@master1 ~]# cat > /etc/keepalived/check_apiserver.sh << 'EOF'
#!/bin/bash
err=0
for k in $(seq 1 3)
do
check_code=$(pgrep nginx)
if [[ $check_code == "" ]]; then
err=$(expr $err + 1)
sleep 1
continue
else
err=0
break
fi
done
if [[ $err != "0" ]]; then
echo "systemctl stop keepalived"
/usr/bin/systemctl stop keepalived
exit 1
else
exit 0
fi
EOF
#给脚本授权
[root@master1 ~]# chmod +x /etc/keepalived/check_apiserver.sh
[root@master2 ~]# yum -y install keepalived.x86_64
[root@master2 ~]# scp master1:/etc/keepalived/{keepalived.conf,check_apiserver.sh} /etc/keepalived/
#修改keepalived配置
[root@master2 ~]# grep -Ev "^#|^$" /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
interval 5
weight -5
fall 2
rise 1
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
mcast_src_ip 192.168.1.22
virtual_router_id 51
priority 90
nopreempt
advert_int 2
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.25
}
track_script {
check_apiserver
}
}
systemctl daemon-reload
systemctl enable nginx --now keepalived
systemctl status nginx keepalived
查看vip
[root@master1 ~]# ip addr | grep -w 192.168.1.25
inet 192.168.1.25/32 scope global ens33
Nginx+keepalived高可用测试
关闭主节点Nginx,测试VIP是否漂移到备节点服务器。
在Nginx Master执行 pkill nginx;
在Nginx Backup,ip addr命令查看已成功绑定VIP。
#创建k8s安装目录
[root@master1 ~]# mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs,manifests,kubeconfig}
#下载地址
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.27.md
#下载安装包,网页直接点击kubernetes-server-linux-amd64.tar.gz 也可下载
[root@master1 ~]# wget https://dl.k8s.io/v1.27.1/kubernetes-server-linux-amd64.tar.gz
#解压k8s安装包
[root@master1 ~]# tar -xf kubernetes-server-linux-amd64.tar.gz --strip-components=3 -C /opt/kubernetes/bin/ kubernetes/server/bin/kube{let,ctl,-apiserver,-controller-manager,-scheduler,-proxy}
#此命令 --strip-components=3:指示tar在提取文件时删除路径的前3个。此命令从kubernetes-server-linux-amd64.tar.gz归档文件中提取以下文件:
[root@master1 ~]# ll /opt/kubernetes/bin/
总用量 473028
-rwxr-xr-x 1 root root 123904000 5月 17 22:22 kube-apiserver
-rwxr-xr-x 1 root root 113246208 5月 17 22:22 kube-controller-manager
-rwxr-xr-x 1 root root 45039616 5月 17 22:22 kubectl
-rwxr-xr-x 1 root root 114263032 5月 17 22:22 kubelet
-rwxr-xr-x 1 root root 41197568 5月 17 22:22 kube-proxy
-rwxr-xr-x 1 root root 46727168 5月 17 22:22 kube-scheduler
[root@master1 ~]# mv /opt/kubernetes/bin/kubectl /usr/local/bin
#查看
[root@master1 ~]# /opt/kubernetes/bin/kubelet --version
Kubernetes v1.27.1
[root@master1 ~]# cd ~/pki/k8s/
[root@master1 k8s]# cat > ca-csr.json << EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "Kubernetes",
"OU": "Kubernetes-manual"
}
],
"ca": {
"expiry": "876000h"
}
}
EOF
#生成根证书
[root@master1 k8s]# cfssl gencert -initca ca-csr.json | cfssljson -bare /opt/kubernetes/ssl/ca
[root@master1 k8s]# cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "876000h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "876000h"
}
}
}
}
EOF
[root@master1 k8s]# cat > apiserver-csr.json << EOF
{
"CN": "kube-apiserver",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "Kubernetes",
"OU": "Kubernetes-manual"
}
]
}
EOF
#生成apiserver证书
[root@master1 k8s]# cfssl gencert \
-ca=/opt/kubernetes/ssl/ca.pem \
-ca-key=/opt/kubernetes/ssl/ca-key.pem \
-config=ca-config.json \
-hostname=10.96.0.1,127.0.0.1,kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.default.svc.cluster.local,192.168.1.21,192.168.1.22,192.168.1.23,192.168.1.25 \
-profile=kubernetes apiserver-csr.json | cfssljson -bare /opt/kubernetes/ssl/apiserver
#上述命令中hostname中的IP为所有Master/LB/VIP IP,一个都不能少,为了方便后期扩容可以多写几个预留的IP。
[root@master1 k8s]# cat > front-proxy-ca-csr.json << EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"ca": {
"expiry": "876000h"
}
}
EOF
[root@master1 k8s]# cfssl gencert -initca front-proxy-ca-csr.json | cfssljson -bare /opt/kubernetes/ssl/front-proxy-ca
[root@master1 k8s]# cat > front-proxy-client-csr.json << 'EOF'
{
"CN": "front-proxy-client",
"key": {
"algo": "rsa",
"size": 2048
}
}
EOF
[root@master1 k8s]# cfssl gencert \
-ca=/opt/kubernetes/ssl/front-proxy-ca.pem \
-ca-key=/opt/kubernetes/ssl/front-proxy-ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
front-proxy-client-csr.json | cfssljson -bare /opt/kubernetes/ssl/front-proxy-client
[root@master1 k8s]# openssl genrsa -out /opt/kubernetes/ssl/sa.key 2048
[root@master1 k8s]# openssl rsa -in /opt/kubernetes/ssl/sa.key -pubout -out /opt/kubernetes/ssl/sa.pub
[root@master1 k8s]# cat > /opt/kubernetes/cfg/kube-apiserver.conf << EOF
KUBE_APISERVER_OPTS="--v=2 \\
--allow-privileged=true \\
--bind-address=0.0.0.0 \\
--secure-port=6443 \\
--advertise-address=192.168.1.21 \\
--service-cluster-ip-range=10.96.0.0/16 \\
--service-node-port-range=30000-32767 \\
--etcd-servers=https://192.168.1.21:2379,https://192.168.1.22:2379,https://192.168.1.23:2379 \\
--etcd-cafile=/opt/etcd/ssl/etcd-ca.pem \\
--etcd-certfile=/opt/etcd/ssl/etcd.pem \\
--etcd-keyfile=/opt/etcd/ssl/etcd-key.pem \\
--client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--tls-cert-file=/opt/kubernetes/ssl/apiserver.pem \\
--tls-private-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--kubelet-client-certificate=/opt/kubernetes/ssl/apiserver.pem \\
--kubelet-client-key=/opt/kubernetes/ssl/apiserver-key.pem \\
--service-account-key-file=/opt/kubernetes/ssl/sa.pub \\
--service-account-signing-key-file=/opt/kubernetes/ssl/sa.key \\
--service-account-issuer=https://kubernetes.default.svc.cluster.local \\
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \
--authorization-mode=Node,RBAC \\
--enable-bootstrap-token-auth=true \\
--requestheader-client-ca-file=/opt/kubernetes/ssl/front-proxy-ca.pem \\
--proxy-client-cert-file=/opt/kubernetes/ssl/front-proxy-client.pem \\
--proxy-client-key-file=/opt/kubernetes/ssl/front-proxy-client-key.pem \\
--requestheader-allowed-names=aggregator \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-extra-headers-prefix=X-Remote-Extra- \\
--requestheader-username-headers=X-Remote-User \\
--enable-aggregator-routing=true"
# --feature-gates=IPv6DualStack=true
# --token-auth-file=/etc/kubernetes/token.csv
EOF
配置参数说明:
--v=2:设置 kube-apiserver 的日志级别为 2。
--allow-privileged=true:允许在集群中运行特权容器。
--bind-address=0.0.0.0:设置 kube-apiserver 绑定的 IP 地址为 0.0.0.0,这意味着它将监听所有网络接口上的请求。
--secure-port=6443:设置 kube-apiserver 监听安全连接的端口号
--advertise-address=192.168.1.25:设置 kube-apiserver 向集群中其他组件宣告的 IP 地址
--service-cluster-ip-range=10.96.0.0/16:设置集群内部服务的 IP 地址范围为 10.96.0.0/16。
--service-node-port-range=30000-32767:设置 NodePort 类型服务的端口号范围为 30000 到 32767。
--etcd-servers=https://192.168.1.21:2379...:设置 etcd 服务器的地址。
--etcd-cafile=/opt/etcd/ssl/etcd-ca.pem:设置 etcd 服务器的 CA 证书文件路径
--etcd-certfile=/opt/etcd/ssl/etcd.pem:设置 etcd 服务器的客户端证书文件路径
--etcd-keyfile=/opt/etcd/ssl/etcd-key.pem:设置 etcd 服务器的客户端密钥文件路径
--client-ca-file=/opt/kubernetes/ssl/ca.pem:设置客户端 CA 证书文件路径
--tls-cert-file=/opt/kubernetes/ssl/apiserver.pem:设置 TLS 证书文件路径
--tls-private-key-file=/opt/kubernetes/ssl/apiserver-key.pem:设置 TLS 私钥文件路径
--kubelet-client-certificate=/opt/kubernetes/ssl/apiserver.pem:设置 kubelet 客户端证书文件路径
--kubelet-client-key=/opt/kubernetes/ssl/apiserver-key.pem:设置 kubelet 客户端密钥文件路径
--service-account-key-file=/opt/kubernetes/ssl/sa.pub:设置服务账号公钥文件路径
--service-account-signing-key-file=/opt/kubernetes/ssl/sa.key:设置服务账号签名私钥文件路径
--service-account-issuer=https://kubernetes.default.svc.cluster.local:设置服务账号颁发者的 URL 为 https://kubernetes.default.svc.cluster.local。
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname:设置 kubelet 的首选地址类型顺序为 InternalIP、ExternalIP 和 Hostname。
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota:启用指定的准入控制插件。这些插件会在创建或修改资源时执行特定的检查和操作,以确保集群的安全性和稳定性。
--authorization-mode=Node,RBAC:启用 Node 和 RBAC 授权模式。这些模式会检查用户或组件对资源的访问权限,以确保集群的安全性和稳定性。
--enable-bootstrap-token-auth=true:启用 bootstrap token 认证。这允许新节点使用 bootstrap token 加入集群。
--requestheader-client-ca-file=/opt/kubernetes/ssl/front-proxy-ca.pem:设置前端代理的 CA 证书文件路径
--proxy-client-cert-file=/opt/kubernetes/ssl/front-proxy-client.pem:设置前端代理的客户端证书文件路径
--proxy-client-key-file=/opt/kubernetes/ssl/front-proxy-client-key.pem:设置前端代理的客户端密钥文件路径
--requestheader-allowed-names=aggregator:设置允许通过前端代理访问 kube-apiserver 的客户端名称为 aggregator。
--requestheader-group-headers=X-Remote-Group:设置前端代理传递用户组信息的 HTTP 头字段名称为 X-Remote-Group。
--requestheader-extra-headers-prefix=X-Remote-Extra-:设置前端代理传递额外用户信息的 HTTP 头字段前缀为 X-Remote-Extra-。
--requestheader-username-headers=X-Remote-User:设置前端代理传递用户名信息的 HTTP 头字段名称为 X-Remote-User。
--enable-aggregator-routing=true":启用聚合层路由。这允许 kube-apiserver 将请求路由到扩展 API 服务器。
[root@master1 k8s]# cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-apiserver.conf
ExecStart=/opt/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure
RestartSec=10s
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
EOF
[root@master1 k8s]# systemctl daemon-reload
[root@master1 k8s]# systemctl enable --now kube-apiserver
[root@master1 k8s]# systemctl status kube-apiserver
#分发文件到master2,如果集群有更多主节点,同操作
[root@master1 k8s]# scp -r /opt/kubernetes master2:/opt/
[root@master1 k8s]# scp -p /usr/local/bin/kubectl master2:/usr/local/bin/kubectl
[root@master1 k8s]# scp /usr/lib/systemd/system/kube-apiserver.service master2:/usr/lib/systemd/system/kube-apiserver.service
##修改配置master2的kube-apiserver.conf对应的IP地址
[root@master2 ~]# cat > /opt/kubernetes/cfg/kube-apiserver.conf << EOF
KUBE_APISERVER_OPTS="--v=2 \\
--allow-privileged=true \\
--bind-address=0.0.0.0 \\
--secure-port=6443 \\
--advertise-address=192.168.1.22 \\
--service-cluster-ip-range=10.96.0.0/16 \\
--service-node-port-range=30000-32767 \\
--etcd-servers=https://192.168.1.21:2379,https://192.168.1.22:2379,https://192.168.1.23:2379 \\
--etcd-cafile=/opt/etcd/ssl/etcd-ca.pem \\
--etcd-certfile=/opt/etcd/ssl/etcd.pem \\
--etcd-keyfile=/opt/etcd/ssl/etcd-key.pem \\
--client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--tls-cert-file=/opt/kubernetes/ssl/apiserver.pem \\
--tls-private-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--kubelet-client-certificate=/opt/kubernetes/ssl/apiserver.pem \\
--kubelet-client-key=/opt/kubernetes/ssl/apiserver-key.pem \\
--service-account-key-file=/opt/kubernetes/ssl/sa.pub \\
--service-account-signing-key-file=/opt/kubernetes/ssl/sa.key \\
--service-account-issuer=https://kubernetes.default.svc.cluster.local \\
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota \
--authorization-mode=Node,RBAC \\
--enable-bootstrap-token-auth=true \\
--requestheader-client-ca-file=/opt/kubernetes/ssl/front-proxy-ca.pem \\
--proxy-client-cert-file=/opt/kubernetes/ssl/front-proxy-client.pem \\
--proxy-client-key-file=/opt/kubernetes/ssl/front-proxy-client-key.pem \\
--requestheader-allowed-names=aggregator \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-extra-headers-prefix=X-Remote-Extra- \\
--requestheader-username-headers=X-Remote-User \\
--enable-aggregator-routing=true"
# --feature-gates=IPv6DualStack=true
# --token-auth-file=/etc/kubernetes/token.csv
EOF
[root@master2 ~]# systemctl daemon-reload
[root@master2 ~]# systemctl enable --now kube-apiserver
[root@master2 ~]# systemctl status kube-apiserver
#测试
curl -k https://192.168.1.21:6443/healthz
ok
curl --insecure https://192.168.1.21:6443/
curl --insecure https://192.168.1.22:6443/
curl --insecure https://192.168.1.25:16443/
[root@master1 k8s]# cat > manager-csr.json << EOF
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "system:kube-controller-manager",
"OU": "Kubernetes-manual"
}
]
}
EOF
[root@master1 k8s]# cfssl gencert \
-ca=/opt/kubernetes/ssl/ca.pem \
-ca-key=/opt/kubernetes/ssl/ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
manager-csr.json | cfssljson -bare /opt/kubernetes/ssl/controller-manager
#上面配置了nginx高可用方案,--server地址为 https://192.168.1.25:16443
#设置一个集群项
[root@master1 k8s]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.1.25:16443 \
--kubeconfig=/opt/kubernetes/kubeconfig/controller-manager.kubeconfig
#设置一个上下文
[root@master1 k8s]# kubectl config set-context system:kube-controller-manager@kubernetes \
--cluster=kubernetes \
--user=system:kube-controller-manager \
--kubeconfig=/opt/kubernetes/kubeconfig/controller-manager.kubeconfig
#设置一个用户项
[root@master1 k8s]# kubectl config set-credentials system:kube-controller-manager \
--client-certificate=/opt/kubernetes/ssl/controller-manager.pem \
--client-key=/opt/kubernetes/ssl/controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=/opt/kubernetes/kubeconfig/controller-manager.kubeconfig
#指定生成kubeconfig文件
[root@master1 k8s]# kubectl config use-context system:kube-controller-manager@kubernetes \
--kubeconfig=/opt/kubernetes/kubeconfig/controller-manager.kubeconfig
[root@master1 k8s]# cat > /opt/kubernetes/cfg/kube-controller-manager.conf << EOF
KUBE_CONTROLLER_MANAGER_OPTS="--v=2 \\
--bind-address=0.0.0.0 \\
--root-ca-file=/opt/kubernetes/ssl/ca.pem \\
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--service-account-private-key-file=/opt/kubernetes/ssl/sa.key \\
--kubeconfig=/opt/kubernetes/kubeconfig/controller-manager.kubeconfig \\
--leader-elect=true \\
--use-service-account-credentials=true \\
--node-monitor-grace-period=40s \\
--node-monitor-period=5s \\
--controllers=*,bootstrapsigner,tokencleaner \\
--allocate-node-cidrs=true \\
--service-cluster-ip-range=10.96.0.0/16 \\
--cluster-cidr=10.244.0.0/16 \\
--node-cidr-mask-size-ipv4=24 \\
--requestheader-client-ca-file=/opt/kubernetes/ssl/front-proxy-ca.pem"
#--node-cidr-mask-size-ipv6=120
# --feature-gates=IPv6DualStack=true
EOF
[root@master1 k8s]# cat > /usr/lib/systemd/system/kube-controller-manager.service << EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-controller-manager.conf
ExecStart=/opt/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=always
RestartSec=10s
[Install]
WantedBy=multi-user.target
EOF
[root@master1 k8s]# systemctl daemon-reload
[root@master1 k8s]# systemctl enable --now kube-controller-manager
[root@master1 k8s]# systemctl status kube-controller-manager
[root@master1 k8s]# scp /opt/kubernetes/cfg/kube-controller-manager.conf master2:/opt/kubernetes/cfg/
[root@master1 k8s]# scp /usr/lib/systemd/system/kube-controller-manager.service master2:/usr/lib/systemd/system/
[root@master1 k8s]# scp /opt/kubernetes/kubeconfig/controller-manager.kubeconfig master2:/opt/kubernetes/kubeconfig/
#启动并查看状态
[root@master2 ~]# systemctl daemon-reload
[root@master2 ~]# systemctl enable --now kube-controller-manager
[root@master2 ~]# systemctl status kube-controller-manager
[root@master1 k8s]# cat > scheduler-csr.json << EOF
{
"CN": "system:kube-scheduler",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "system:kube-scheduler",
"OU": "Kubernetes-manual"
}
]
}
EOF
[root@master1 k8s]# cfssl gencert \
-ca=/opt/kubernetes/ssl/ca.pem \
-ca-key=/opt/kubernetes/ssl/ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
scheduler-csr.json | cfssljson -bare /opt/kubernetes/ssl/scheduler
[root@master1 k8s]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.1.25:16443 \
--kubeconfig=/opt/kubernetes/kubeconfig/scheduler.kubeconfig
[root@master1 k8s]# kubectl config set-credentials system:kube-scheduler \
--client-certificate=/opt/kubernetes/ssl/scheduler.pem \
--client-key=/opt/kubernetes/ssl/scheduler-key.pem \
--embed-certs=true \
--kubeconfig=/opt/kubernetes/kubeconfig/scheduler.kubeconfig
[root@master1 k8s]# kubectl config set-context system:kube-scheduler@kubernetes \
--cluster=kubernetes \
--user=system:kube-scheduler \
--kubeconfig=/opt/kubernetes/kubeconfig/scheduler.kubeconfig
[root@master1 k8s]# kubectl config use-context system:kube-scheduler@kubernetes \
--kubeconfig=/opt/kubernetes/kubeconfig/scheduler.kubeconfig
[root@master1 k8s]# cat > /opt/kubernetes/cfg/scheduler.conf << 'EOF'
KUBE_SCHEDULER_OPTS="--v=2 \
--bind-address=0.0.0.0 \
--leader-elect=true \
--kubeconfig=/opt/kubernetes/kubeconfig/scheduler.kubeconfig"
EOF
[root@master1 k8s]# cat > /usr/lib/systemd/system/kube-scheduler.service << 'EOF'
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
EnvironmentFile=/opt/kubernetes/cfg/scheduler.conf
ExecStart=/opt/kubernetes/bin/kube-scheduler $KUBE_SCHEDULER_OPTS
Restart=always
RestartSec=10s
[Install]
WantedBy=multi-user.target
EOF
[root@master1 k8s]# systemctl daemon-reload
[root@master1 k8s]# systemctl enable --now kube-scheduler
[root@master1 k8s]# systemctl status kube-scheduler
[root@master1 k8s]# scp /opt/kubernetes/cfg/scheduler.conf master2:/opt/kubernetes/cfg/
[root@master1 k8s]# scp /usr/lib/systemd/system/kube-scheduler.service master2:/usr/lib/systemd/system/
[root@master1 k8s]# scp /opt/kubernetes/kubeconfig/scheduler.kubeconfig master2:/opt/kubernetes/kubeconfig/
#启动服务
[root@master2 ~]# systemctl daemon-reload
[root@master2 ~]# systemctl enable --now kube-scheduler
[root@master2 ~]# systemctl status kube-scheduler
kubectl 与 apiserver https 安全端口通信,apiserver 对提供的证书进行认证和授权。
kubectl 作为集群的管理工具,需要被授予最高权限。这里创建具有最高权限的 admin 证书。
[root@master1 k8s]# cat > admin-csr.json << EOF
{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "system:masters",
"OU": "Kubernetes-manual"
}
]
}
EOF
[root@master1 k8s]# cfssl gencert \
-ca=/opt/kubernetes/ssl/ca.pem \
-ca-key=/opt/kubernetes/ssl/ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
admin-csr.json | cfssljson -bare /opt/kubernetes/ssl/admin
kube.config 为 kubectl 的配置文件,包含访问 apiserver 的所有信息,如 apiserver 地址、CA 证书和自身使用的证书。
[root@master1 k8s]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.1.25:16443 \
--kubeconfig=/opt/kubernetes/kubeconfig/admin.kubeconfig
[root@master1 k8s]# kubectl config set-credentials kubernetes-admin \
--client-certificate=/opt/kubernetes/ssl/admin.pem \
--client-key=/opt/kubernetes/ssl/admin-key.pem \
--embed-certs=true \
--kubeconfig=/opt/kubernetes/kubeconfig/admin.kubeconfig
[root@master1 k8s]# kubectl config set-context kubernetes-admin@kubernetes \
--cluster=kubernetes \
--user=kubernetes-admin \
--kubeconfig=/opt/kubernetes/kubeconfig/admin.kubeconfig
[root@master1 k8s]# kubectl config use-context kubernetes-admin@kubernetes --kubeconfig=/opt/kubernetes/kubeconfig/admin.kubeconfig
[root@master1 k8s]# mkdir -p /root/.kube
[root@master1 k8s]# cp /opt/kubernetes/kubeconfig/admin.kubeconfig /root/.kube/config
[root@master1 k8s]# scp -r /root/.kube/ master2:/root/
#查看集群信息
[root@master1 k8s]# kubectl cluster-info
Kubernetes control plane is running at https://192.168.1.25:16443
#查看集群组件状态
[root@master1 k8s]# 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-1 Healthy {"health":"true","reason":""}
etcd-0 Healthy {"health":"true","reason":""}
#查看命名空间中资源对象
[root@master1 k8s]# kubectl get all --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 54m
下面还是在master1上面操作,即当Master节点,也当Work Node节点
#/dev/urandom是一个产生高质量随机数的设备文件。tr用于删除控制字符,fold用于限制每行的字符数,head提取第一行
#token-id
[root@test k8s]# cat /dev/urandom |tr -dc 'a-z0-9' | fold -w 6 | head -n 1
qfxsz4
#token-secret
[root@test k8s]# cat /dev/urandom |tr -dc 'a-z0-9' | fold -w 16 | head -n 1
emer1gzx3shzbf2t
#配置集群中的 bootstrap token 和相关的 RBAC 角色绑定,用于控制对集群资源的访问权限。
[root@master1 k8s]# cat > /opt/kubernetes/cfg/bootstrap.secret.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
name: bootstrap-token-qfxsz4
namespace: kube-system
type: bootstrap.kubernetes.io/token
stringData:
description: "The default bootstrap token generated by 'kubelet '."
token-id: qfxsz4
token-secret: emer1gzx3shzbf2t
usage-bootstrap-authentication: "true"
usage-bootstrap-signing: "true"
auth-extra-groups: system:bootstrappers:default-node-token,system:bootstrappers:worker,system:bootstrappers:ingress
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubelet-bootstrap
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:node-bootstrapper
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:default-node-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-autoapprove-bootstrap
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:default-node-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-autoapprove-certificate-rotation
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:nodes
---
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
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: kube-apiserver
EOF
#执行上述文件,一定要执行
[root@master1 k8s]# kubectl apply -f /opt/kubernetes/cfg/bootstrap.secret.yaml
kubeconfig 文件用于 kubelet 初次加入集群时进行引导
[root@master1 k8s]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true --server=https://192.168.1.25:16443 \
--kubeconfig=/opt/kubernetes/kubeconfig/bootstrap-kubelet.kubeconfig
[root@master1 k8s]# kubectl config set-credentials tls-bootstrap-token-user \
--token=qfxsz4.emer1gzx3shzbf2t \
--kubeconfig=/opt/kubernetes/kubeconfig/bootstrap-kubelet.kubeconfig
[root@master1 k8s]# kubectl config set-context tls-bootstrap-token-user@kubernetes \
--cluster=kubernetes \
--user=tls-bootstrap-token-user \
--kubeconfig=/opt/kubernetes/kubeconfig/bootstrap-kubelet.kubeconfig
[root@master1 k8s]# kubectl config use-context tls-bootstrap-token-user@kubernetes \
--kubeconfig=/opt/kubernetes/kubeconfig/bootstrap-kubelet.kubeconfig
###说明:
#token必须和bootstrap.secret.yaml 中的token相对应
[root@master1 k8s]# cat > /opt/kubernetes/cfg/kubelet-conf.yml << EOF
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: 0.0.0.0
port: 10250
readOnlyPort: 10255
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /opt/kubernetes/ssl/ca.pem
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
cgroupDriver: systemd
cgroupsPerQOS: true
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
containerLogMaxFiles: 5
containerLogMaxSize: 10Mi
contentType: application/vnd.kubernetes.protobuf
cpuCFSQuota: true
cpuManagerPolicy: none
cpuManagerReconcilePeriod: 10s
enableControllerAttachDetach: true
enableDebuggingHandlers: true
enforceNodeAllocatable:
- pods
eventBurst: 10
eventRecordQPS: 5
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
nodefs.inodesFree: 5%
evictionPressureTransitionPeriod: 5m0s
failSwapOn: true
fileCheckFrequency: 20s
hairpinMode: promiscuous-bridge
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 20s
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 80
imageMinimumGCAge: 2m0s
iptablesDropBit: 15
iptablesMasqueradeBit: 14
kubeAPIBurst: 10
kubeAPIQPS: 5
makeIPTablesUtilChains: true
maxOpenFiles: 1000000
maxPods: 110
nodeStatusUpdateFrequency: 10s
oomScoreAdj: -999
podPidsLimit: -1
registryBurst: 10
registryPullQPS: 5
resolvConf: /etc/resolv.conf
rotateCertificates: true
runtimeRequestTimeout: 2m0s
serializeImagePulls: true
staticPodPath: /opt/kubernetes/manifests
streamingConnectionIdleTimeout: 4h0m0s
syncFrequency: 1m0s
volumeStatsAggPeriod: 1m0s
EOF
[root@master1 k8s]# cat > /usr/lib/systemd/system/kubelet.service << EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service
[Service]
ExecStart=/opt/kubernetes/bin/kubelet \\
--bootstrap-kubeconfig=/opt/kubernetes/kubeconfig/bootstrap-kubelet.kubeconfig \\
--kubeconfig=/opt/kubernetes/kubeconfig/kubelet.kubeconfig \\
--config=/opt/kubernetes/cfg/kubelet-conf.yml \\
--container-runtime-endpoint=unix:///run/containerd/containerd.sock \\
--node-labels=node.kubernetes.io/node=
# --feature-gates=IPv6DualStack=true
# --container-runtime=remote
# --runtime-request-timeout=15m
# --cgroup-driver=systemd
[Install]
WantedBy=multi-user.target
EOF
[root@master1 k8s]# systemctl daemon-reload
[root@master1 k8s]# systemctl enable --now kubelet
[root@master1 k8s]# systemctl status kubelet
查看集群节点
[root@master1 k8s]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 Ready <none> 42s v1.27.1
#查看容器运行时
[root@master1 k8s]# kubectl describe node | grep Runtime
Container Runtime Version: containerd://1.7.1
[root@master1 ~]# for i in {master2,node1}
do
ssh $i "mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs,manifests,kubeconfig}"
scp /opt/kubernetes/bin/kubelet $i:/opt/kubernetes/bin
scp /opt/kubernetes/kubeconfig/bootstrap-kubelet.kubeconfig $i:/opt/kubernetes/kubeconfig/
scp /opt/kubernetes/cfg/kubelet-conf.yml $i:/opt/kubernetes/cfg/
scp -r /opt/kubernetes/ssl/ca.pem $i:/opt/kubernetes/ssl/
scp /usr/lib/systemd/system/kubelet.service $i:/usr/lib/systemd/system/
done
[root@master1 ~]# for i in {master2,node1}
do
ssh $i "systemctl daemon-reload;systemctl enable --now kubelet"
done
#查看节点,全都加入集群
[root@master1 k8s]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 Ready <none> 18m v1.27.1
master2 Ready <none> 6m32s v1.27.1
node1 Ready <none> 25s v1.27.1
[root@master1 k8s]# cat > kube-proxy-csr.json << EOF
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "system:kube-proxy",
"OU": "Kubernetes-manual"
}
]
}
EOF
[root@master1 k8s]# cfssl gencert \
-ca=/opt/kubernetes/ssl/ca.pem \
-ca-key=/opt/kubernetes/ssl/ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-proxy-csr.json | cfssljson -bare /opt/kubernetes/ssl/kube-proxy
[root@master1 k8s]# kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=https://192.168.1.25:16443 \
--kubeconfig=/opt/kubernetes/kubeconfig/kube-proxy.kubeconfig
[root@master1 k8s]# kubectl config set-credentials kube-proxy \
--client-certificate=/opt/kubernetes/ssl/kube-proxy.pem \
--client-key=/opt/kubernetes/ssl/kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=/opt/kubernetes/kubeconfig/kube-proxy.kubeconfig
[root@master1 k8s]# kubectl config set-context kube-proxy@kubernetes \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=/opt/kubernetes/kubeconfig/kube-proxy.kubeconfig
[root@master1 k8s]# kubectl config use-context kube-proxy@kubernetes --kubeconfig=/opt/kubernetes/kubeconfig/kube-proxy.kubeconfig
[root@master1 k8s]# cat > /opt/kubernetes/cfg/kube-proxy.yaml << EOF
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
clientConnection:
acceptContentTypes: ""
burst: 10
contentType: application/vnd.kubernetes.protobuf
kubeconfig: /opt/kubernetes/kubeconfig/kube-proxy.kubeconfig
qps: 5
clusterCIDR: 10.244.0.0/16
configSyncPeriod: 15m0s
conntrack:
max: null
maxPerCore: 32768
min: 131072
tcpCloseWaitTimeout: 1h0m0s
tcpEstablishedTimeout: 24h0m0s
enableProfiling: false
healthzBindAddress: 0.0.0.0:10256
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: 14
minSyncPeriod: 0s
syncPeriod: 30s
ipvs:
masqueradeAll: true
minSyncPeriod: 5s
scheduler: "rr"
syncPeriod: 30s
kind: KubeProxyConfiguration
metricsBindAddress: 127.0.0.1:10249
mode: "ipvs"
nodePortAddresses: null
oomScoreAdj: -999
portRange: ""
udpIdleTimeout: 250ms
EOF
[root@master1 k8s]# cat > /usr/lib/systemd/system/kube-proxy.service << EOF
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes
After=network.target
[Service]
ExecStart=/opt/kubernetes/bin/kube-proxy \\
--config=/opt/kubernetes/cfg/kube-proxy.yaml \\
--v=2
Restart=always
RestartSec=10s
[Install]
WantedBy=multi-user.target
EOF
[root@master1 k8s]# systemctl daemon-reload
[root@master1 k8s]# systemctl enable --now kube-proxy
[root@master1 k8s]# systemctl status kube-proxy
[root@master1 k8s]# for i in {master2,node1}
do
scp /opt/kubernetes/bin/kube-proxy $i:/opt/kubernetes/bin/
scp /opt/kubernetes/kubeconfig/kube-proxy.kubeconfig $i:/opt/kubernetes/kubeconfig/
scp /opt/kubernetes/cfg/kube-proxy.yaml $i:/opt/kubernetes/cfg/
scp /usr/lib/systemd/system/kube-proxy.service $i:/usr/lib/systemd/system/
ssh $i "systemctl daemon-reload;systemctl enable --now kube-proxy"
done
此文将采用离线方法部署calico,在线部署同理
在规划的 192.168.1.9 上操作
#下载安装包
[root@docker-registry ~]# wget https://download.docker.com/linux/static/stable/x86_64/docker-24.0.1.tgz
#解压缩并配置文件
[root@docker-registry ~]# tar -xf docker-24.0.1.tgz
[root@docker-registry ~]# mv docker/* /usr/bin/
[root@docker-registry ~]# cat > /etc/systemd/system/docker.service << EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP \$MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
EOF
#设置docker存储目录到大硬盘目录、设置私有镜像仓库地址(可选,注意替换目录位置与私有镜像仓库URL),配置国内镜像加速
[root@docker-registry ~]# mkdir /etc/docker
[root@docker-registry ~]# mkdir -p /data/docker
[root@docker-registry ~]# cat > /etc/docker/daemon.json << 'EOF'
{
"insecure-registries":["192.168.1.9:5000"],
"data-root":"/data/docker",
"registry-mirrors": ["https://l32efr19.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "20m"
}
}
EOF
#配置镜像加速方法
登录阿里云https://www.aliyun.com/,搜索容器镜像服务,登录后点击:左侧栏镜像工具-镜像加速器
{
"registry-mirrors": ["https://l32efr19.mirror.aliyuncs.com"]
}
[root@docker-registry ~]# systemctl daemon-reload
[root@docker-registry ~]# systemctl daemon-reload
[root@docker-registry ~]# systemctl enable --now docker
[root@docker-registry ~]# mkdir /data/registry
[root@docker-registry ~]# docker run -d \
-p 5000:5000 \
--restart=always \
--name=registry \
-v /opt/myregistry:/var/lib/registry \
registry
#至此一个简易的镜像仓库搭建完成,不用的话直接删除即可
[root@registry ~]# docker rm registry
在我的CSDN资源里可自行下载
[root@docker-registry ~]# cd calico3.25/
[root@docker-registry ~]# docker load -i calico_cni-v3.25.0.tar
[root@docker-registry ~]# docker tag d70a5947d57e 192.168.1.9:5000/cni:v3.25.0
[root@docker-registry ~]# docker push 192.168.1.9:5000/cni:v3.25.0
[root@docker-registry ~]# docker load -i calico_kube-controllers-v3.25.0.tar
[root@docker-registry ~]# docker tag 5e785d005ccc 192.168.1.9:5000/kube-
[root@docker-registry ~]# docker push 192.168.1.9:5000/kube-controllers:v3.25.0
[root@docker-registry ~]# docker load -i calico_node-v3.25.0.tar
[root@docker-registry ~]# docker tag 08616d26b8e7 192.168.1.9:5000/node:v3.25.0
[root@docker-registry ~]# docker push 192.168.1.9:5000/node:v3.25.0
官网https://docs.tigera.io/archive 查询文档,选择合适的calico版本
#centos7 最好要升级libseccomp
[root@master1 ~]# yum -y install http://rpmfind.net/linux/centos/8-stream/BaseOS/x86_64/os/Packages/libseccomp-2.5.1-1.el8.x86_64.rpm
[root@master1 ~]# rpm -qa | grep libseccomp
[root@master1 ~]# mkdir calico3.25
[root@master1 ~]# cd calico3.25
[root@master1 calico3.25]# curl https://docs.projectcalico.org/archive/v3.25/manifests/calico.yaml -O
#修改默认网桥
把calico.yaml里pod所在网段改成 --cluster-cidr=10.244.0.0/16 时选项所指定的网段,
直接用vim编辑打开此文件查找192,按如下标记进行修改:
# no effect. This should fall within `--cluster-cidr`.
# - name: CALICO_IPV4POOL_CIDR
# value: "192.168.1.0/16"
# Disable file logging so `kubectl logs` works.
- name: CALICO_DISABLE_FILE_LOGGING
value: "true"
把两个#及#后面的空格去掉,并把192.168.1.0/16改成10.244.0.0/16
# no effect. This should fall within `--cluster-cidr`.
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16"
# Disable file logging so `kubectl logs` works.
- name: CALICO_DISABLE_FILE_LOGGING
value: "true"
#由于yaml文件中的镜像是国外的,建议提前拉取镜像再部署,减少由于直接安装时,镜像拉取失败,导致的安装失败
[root@master1 calico3.25]# grep "image:" calico.yaml | uniq
image: docker.io/calico/cni:v3.25.0
image: docker.io/calico/node:v3.25.0
image: docker.io/calico/kube-controllers:v3.25.0
[root@master1 calico3.25]# sed -i s#docker.io/calico#192.168.1.9:5000# calico.yaml
[root@master1 calico3.25]# kubectl apply -f calico.yaml
[root@master1 calico3.25]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-5bbfbcdcdc-zz8wt 1/1 Running 0 30s
calico-node-7qvb7 1/1 Running 0 30s
calico-node-bwxsd 1/1 Running 0 30s
calico-node-xzl2q 1/1 Running 0 30s
#差不多不到1分钟左右即可安装完成,如果用的官网上的镜像,网络可以的话,大概10多分钟。
coredns: Kubernetes内部域名解析
coredns在K8S中的用途,主要是用作服务发现,也就是服务(应用)之间相互定位的过程。
Server实现了POD地址的固定,DNS可以实现访问Server的名称访问到POD(服务发现)
对于一些服务提前不知道Server地址,但是要基于服务配置,就可以直接使用Server的名称,后期只要创建这样名称即可
为什么需要服务发现
在K8S集群中,POD有以下特性:
a、服务动态性强
容器在k8s中迁移会导致POD的IP地址变化
b、更新发布频繁
版本迭代快,新旧POD的IP地址会不同
c、支持自动伸缩
大促或流量高峰需要动态伸缩,IP地址会动态增减
service资源解决POD服务发现:
为了解决pod地址变化的问题,需要部署service资源,用service资源代理后端pod,通过暴露service资源的固定地址(集群IP),来解决以上POD资源变化产生的IP变动问题
那service资源的服务发现呢?
service资源提供了一个不变的集群IP供外部访问,但
a、IP地址毕竟难以记忆
b、service资源可能也会被销毁和创建
c、能不能将service资源名称和service暴露的集群网络IP对于
d、类似域名与IP关系,则只需记服务名就能自动匹配服务
e、IP岂不就达到了service服务的自动发现
在k8s中,coredns就是为了解决以上问题。
coredns域名解析流程:
当pod1应用想通过dns域名的方式访问pod2则首先根据容器中/etc/resolv.conf内容配置的namserver地址,向dns服务器发出请求,由service将请求抛出转发给kube-dns service,由它进行调度后端的core-dns进行域名解析。解析后请求给kubernetes service进行调度后端etcd数据库返回数据,pod1得到数据后由core-dns转发目的pod2地址解析,最终pod1请求得到pod2
coredns是不负责存储域名解析记录的,是通过apiserver。它是K8S内部的,集群内的各pod与K8S的API server联系都是通过这个10.96.0.1地址联系的,这个地址是K8S集群内API server的服务地址
[root@docker-registry ~]# docker pull busybox
[root@docker-registry ~]# docker tag beae173ccac6 192.168.1.9:5000/busybox:latest
[root@docker-registry ~]# docker push 192.168.1.9:5000/busybox:latest
[root@master1 ~]# kubectl run -it --rm --restart=Never --image=192.168.1.9:5000/busybox:latest busybox
If you don't see a command prompt, try pressing enter.
/ # cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
/ # nslookup kubernetes
;; connection timed out; no servers could be reached
#上面表明无法进行解析
官网 https://coredns.io/
https://github.com/coredns/
进入 https://github.com,搜索coredns,跳转出页面点击coredns/deployment
点击 coredns/deployment - 点击 kubernetes - 点击coredns.yaml.sed,就可以看见文件内容了,下载下来进行修改即可
完整地址
https://github.com/coredns/deployment/tree/master/kubernetes
https://github.com/coredns/deployment/blob/master/kubernetes/coredns.yaml.sed
下载三个文件
coredns.yaml.sed deploy.sh rollback.sh #下载前2个就够了
[root@master1 ~]# grep clusterDNS -A 1 /opt/kubernetes/cfg/kubelet-conf.yml
clusterDNS:
- 10.96.0.10
cp coredns.yaml.sed coredns.yaml
cat deploy.sh
...
sed -e "s/CLUSTER_DNS_IP/$CLUSTER_DNS_IP/g" \
-e "s/CLUSTER_DOMAIN/$CLUSTER_DOMAIN/g" \
-e "s?REVERSE_CIDRS?$REVERSE_CIDRS?g" \
-e "s@STUBDOMAINS@${STUBDOMAINS//$orig/$replace}@g" \
-e "s/UPSTREAMNAMESERVER/$UPSTREAM/g" \
"${YAML_TEMPLATE}"
脚本提示coredns.yaml有5个地方需要根据集群情况修改
CLUSTER_DNS_IP 10.96.0.10
kubernetes CLUSTER_DOMAIN REVERSE_CIDRS { kubernetes cluster.local in-addr.arpa ip6.arpa {
STUBDOMAINS 删掉
UPSTREAMNAMESERVER /etc/resolv.conf
#所有修改的地方整理出来
[root@master1 ~]# sed -i -e "s/CLUSTER_DNS_IP/10.96.0.10/g" \
-e "s/CLUSTER_DOMAIN/cluster.local/g" \
-e "s/REVERSE_CIDRS/in-addr.arpa\ ip6.arpa/g" \
-e "s/STUBDOMAINS//g" \
-e "s#UPSTREAMNAMESERVER#/etc/resolv.conf#g" coredns.yaml
#上传镜像包并推送到镜像仓库
[root@dockerregistry ~]# docker load -i coredns_1.9.4.tar
[root@dockerregistry ~]# docker tag a81c2ec4e946 192.168.1.9:5000/coredns:1.9.4
[root@dockerregistry ~]# docker push 192.168.1.9:5000/coredns:1.9.4
[root@master1 ~]# sed -i s#coredns/coredns#192.168.1.9:5000/coredns# coredns.yaml
#安装
[root@master1 ~]# kubectl apply -f coredns.yaml
#查看
[root@master1 ~]# kubectl get service -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 8s
#查看coredns服务,默认是一个副本
[root@master1 ~]# kubectl get pod -A | grep core
kube-system coredns-5dc594fd48-c2znc 1/1 Running 0 26s
[root@master1 ~]# kubectl run -it --rm --restart=Never --image=192.168.1.9:5000/busybox:latest busybox
If you don't see a command prompt, try pressing enter.
/ # nslookup kubernetes
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
[root@master1 ~]# cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: 192.168.1.9:5000/busybox:latest
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
[root@master1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25h
[root@master1 ~]# kubectl get po -n kube-system -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
calico-kube-controllers-5bbfbcdcdc-zz8wt 1/1 Running 1 (3h2m ago) 23h 10.244.180.1 master2 <none> <none>
calico-node-7qvb7 1/1 Running 1 (3h2m ago) 23h 192.168.1.21 master1 <none> <none>
calico-node-bwxsd 1/1 Running 1 (3h2m ago) 23h 192.168.1.22 master2 <none> <none>
calico-node-xzl2q 1/1 Running 1 (3h2m ago) 23h 192.168.1.23 node1 <none> <none>
coredns-5dc594fd48-c2znc 1/1 Running 0 65m 10.244.137.75 master1 <none> <none>
# 进入busybox ping其他节点上的 pod
[root@master1 ~]# kubectl exec -it busybox -- sh
/ # ping 192.168.1.23 -w 2
PING 192.168.1.23 (192.168.1.23): 56 data bytes
64 bytes from 192.168.1.23: seq=0 ttl=63 time=0.279 ms
64 bytes from 192.168.1.23: seq=1 ttl=63 time=0.156 ms
/ # ping 10.244.137.75 -w 2
PING 10.244.137.75 (10.244.137.75): 56 data bytes
64 bytes from 10.244.137.75: seq=0 ttl=62 time=0.427 ms
64 bytes from 10.244.137.75: seq=1 ttl=62 time=0.193 ms
官方网址: https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/
无特别要求可以直接按照官网提示直接安装 kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml
本次采用下载yaml到本地再运行,使用NodePort方式运行dashboard,使之可以在web页面访问
[root@master1 ~]# wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml
[root@master1 ~]# vim recommended.yaml
...
32 kind: Service
33 apiVersion: v1
34 metadata:
35 labels:
36 k8s-app: kubernetes-dashboard
37 name: kubernetes-dashboard
38 namespace: kubernetes-dashboard
39 spec:
40 type: NodePort #在39行下面添加
41 ports:
42 - port: 443
43 targetPort: 8443
44 nodePort: 30001 #添加一行定义对外的访问端口
45 selector:
46 k8s-app: kubernetes-dashboard
...
#上传dashboard-v2.5.0 包到docker-registry,将镜像推送到私有仓库
[root@docker-registry ~]# cd dashboard-v2.5.0/
#总共两个镜像包
[root@docker-registry dashboard-v2.5.0]# grep "image:" recommended.yaml
image: kubernetesui/dashboard:v2.5.0
image: kubernetesui/metrics-scraper:v1.0.7
[root@docker-registry dashboard-v2.5.0]# docker load -i dashboard-v2.5.0.tar
[root@docker-registry dashboard-v2.5.0]# docker tag 57446aa2002e 192.168.1.9:5000/dashboard:v2.5.0
[root@docker-registry dashboard-v2.5.0]# docker push 192.168.1.9:5000/dashboard:v2.5.0
[root@docker-registry dashboard-v2.5.0]# docker load -i metrics-scraper-v1.0.7.tar
[root@docker-registry dashboard-v2.5.0]# docker images | grep metrics
kubernetesui/metrics-scraper v1.0.7 7801cfc6d5c0 2 years ago 34.4MB
[root@docker-registry dashboard-v2.5.0]# docker tag 7801cfc6d5c0 192.168.1.9:5000/metrics-scraper:v1.0.7
[root@docker-registry dashboard-v2.5.0]# docker push 192.168.1.9:5000/metrics-scraper:v1.0.7
#修改镜像地址
[root@master1 ~]# sed -i s/kubernetesui/192.168.1.9:5000/g recommended.yaml
#部署
[root@master1 ~]# kubectl apply -f recommended.yaml
#查看服务
[root@master1 ~]# kubectl get pods,svc -n kubernetes-dashboard
NAME READY STATUS RESTARTS AGE
pod/dashboard-metrics-scraper-69996c49db-dzzgp 1/1 Running 0 14s
pod/kubernetes-dashboard-6c68b8b59c-nsb8q 1/1 Running 0 14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/dashboard-metrics-scraper ClusterIP 10.96.9.242 <none> 8000/TCP 14s
service/kubernetes-dashboard NodePort 10.96.175.237 <none> 443:30001/TCP 14s
默认是https://master_ip:30001/
https://192.168.1.21:30001/
由于证书原因,如果使用谷歌网址进不去,可以使用火狐登录。
dashboard有两种登陆方式,一种是Token方式,另外一种是使用kubeconfig方式
#创建一个叫 dashboard-admin 的账号,并指定命名空间为kube-system
[root@master1 ~]# kubectl create serviceaccount dashboard-admin -n kube-system
serviceaccount/dashboard-admin created
#创建一个关系,关系名为dashboard-admin,角色为cluster-admin,账户为kube-system命名空间下的dashboard-admin账号
[root@master1 ~]# kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
clusterrolebinding.rbac.authorization.k8s.io/dashboard-admin created
#创建token
[root@master1 ~]# kubectl -n kube-system create token dashboard-admin
eyJhbGciOiJSUzI1NiIsImtpZCI6IllVZ3ZxTmh0RTNyZkZiZ0FvS3FqSk0tWmZRYTRZWGFIQW1jbzNNMnBjU1kifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjkyNzIwODA4LCJpYXQiOjE2OTI3MTcyMDgsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkYXNoYm9hcmQtYWRtaW4iLCJ1aWQiOiJmYzdkNTFmYi0xMmE0LTRjMjItYTdiMy1jMmY5MTJiYzRlMzIifX0sIm5iZiI6MTY5MjcxNzIwOCwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.op9WREunCFPbE-G-8VK5Oz-neCQCqaWd16a3goP33wvjmhdN2C_bVKdhk9pr_aVZ8MwraIGN-6rSnmi8ySSC2pJxPjyHJJJpuRjqO0qe39YO5cXFF_JDOGt27Xoi9U43zSR5KEW4gyIyAR71L72bJos0tmYEgIlEhIoaEIcag3KaD8V9kEbkZlVTUQ2pMhXUt3CzNeOUMfEAlw7e9HPTtpw6HMkCKmo9J-NVshkaP6zzpNecj-nX9bFVkjJr-M7bD7iRNJZkQoQnF9w8er18R9hXzFrBBY4y6PXPU2mbVwDJxHIB2zdR-ft-hTu3J7dxbb661gIeE0PhNhhRwBZscw
#上面操作步骤创建serviceaccount和clusterrolebinding,也可以写成yaml文件,通过kubectl apply ...创建
cat > dashboard-user.yaml << EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: dashboard-admin
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dashboard-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: dashboard-admin
namespace: kube-system
EOF
kubectl apply -f dashboard-user.yaml
kubectl -n kube-system create token dashboard-admin
复制token到dashboard
登录,安装完成
官网地址: https://github.com/kubernetes-sigs/metrics-server
介绍:
Kubernetes Metrics Server 是 Kubernetes 集群的核心监控数据聚合器。它从 Kubelet 收集资源指标,并通过 Metrics API 在 Kubernetes APIServer 中提供给缩放资源对象 HPA 使用。您也可以通过 Metrics API 提供的 Kubectl top 查看 Pod 资源占用情况,从而实现对资源的自动缩放1。
Metrics Server 提供了以下功能:
查看 metrics-server(或者其他资源指标 API metrics.k8s.io
服务提供者)是否正在运行,键入以下命令查看:
如果资源指标 API 可用,则会输出将包含一个对 metrics.k8s.io
的引用。目前我还没有安装。
[root@master1 ~]# kubectl get apiservices
NAME SERVICE AVAILABLE AGE
v1. Local True 17h
v1.admissionregistration.k8s.io Local True 17h
v1.apiextensions.k8s.io Local True 17h
v1.apps Local True 17h
v1.authentication.k8s.io Local True 17h
v1.authorization.k8s.io Local True 17h
v1.autoscaling Local True 17h
v1.batch Local True 17h
v1.certificates.k8s.io Local True 17h
v1.coordination.k8s.io Local True 17h
v1.crd.projectcalico.org Local True 26m
v1.discovery.k8s.io Local True 17h
v1.events.k8s.io Local True 17h
v1.networking.k8s.io Local True 17h
v1.node.k8s.io Local True 17h
v1.policy Local True 17h
v1.rbac.authorization.k8s.io Local True 17h
v1.scheduling.k8s.io Local True 17h
v1.storage.k8s.io Local True 17h
v1beta2.flowcontrol.apiserver.k8s.io Local True 17h
v1beta3.flowcontrol.apiserver.k8s.io Local True 17h
v2.autoscaling Local True 17h
#下载yaml文件
#单机版
https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.3/components.yaml
#高可用版本
[root@master1 ~]# wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.3/high-availability.yaml
#上传镜像包,官网镜像包拉取不下来
[root@docker-registry ~]# docker load -i metrics-server_v0.6.3.tar
[root@docker-registry ~]# docker tag 817bbe3f2e51 192.168.1.9:5000/metrics-server:v0.6.3
[root@docker-registry ~]# docker push 192.168.1.9:5000/metrics-server:v0.6.3
#修改yaml文件,配置证书
[root@master1 ~]# vim high-availability.yaml
#1
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls
- --requestheader-client-ca-file=/opt/kubernetes/ssl/front-proxy-ca.pem
- --requestheader-username-headers=X-Remote-User
- --requestheader-group-headers=X-Remote-Group
- --requestheader-extra-headers-prefix=X-Remote-Extra-
#2
volumeMounts:
- mountPath: /tmp
name: tmp-dir
- name: ca-ssl
mountPath: /opt/kubernetes/ssl
#3
volumes:
- emptyDir: {}
name: tmp-dir
- name: ca-ssl
hostPath:
path: /opt/kubernetes/ssl
#4 将 policy/v1beta1 改成 policy/v1
---
apiVersion: policy/v1
kind: PodDisruptionBudget
#修改yaml文件镜像地址
[root@master1 ~]# sed -i s#registry.k8s.io/metrics-server#192.168.1.9:5000#g high-availability.yaml
配置的是2个节点,会在三个节点上随机选择两个节点安装,node1上ssl文件没有同步,我们同步过去,不然安装会一直 CrashLoopBackOff
[root@master1 ~]# scp /opt/kubernetes/ssl/ node1:/opt/kubernetes/ssl/
#执行安装
[root@master1 ~]# kubectl apply -f high-availability.yaml
[root@master1 ~]# kubectl get pod -n kube-system -owide | grep metrics-server
metrics-server-7f447d95f6-lq6cr 1/1 Running 0 5m49s 10.244.137.81 master1
metrics-server-7f447d95f6-vlt88 1/1 Running 0 2m44s 10.244.166.133 node1
[root@master1 ~]# kubectl get apiservices | grep metrics-server
v1beta1.metrics.k8s.io kube-system/metrics-server True 6m7s
[root@master1 ~]# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master1 209m 10% 1303Mi 34%
master2 216m 10% 1251Mi 33%
node1 145m 7% 676Mi 36%
[root@master1 ~]# kubectl top pod busybox
NAME CPU(cores) MEMORY(bytes)
busybox 0m 0Mi
K8s集群对外暴露服务的方式:
ClusterIP
Clusterip是集群内部的私有ip,在集群内部访问服务非常方便,也是kuberentes集群默认的方式,直接通过service的Clusterip访问,也可以直接通过ServiceName访问。集群外部则是无法访问的
NodePort
NodePort 服务是引导外部流量到你的服务的最原始方式。NodePort,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。
NodePort 服务特征如下:
每个端口只能是一种服务
端口范围只能是 30000-32767(可调)
不在 YAML 配置文件中指定则会分配一个默认端口
LoadBalancer
LoadBlancer Service 是 kubernetes 深度结合云平台的一个组件;当使用 LoadBlancer Service 暴露服务时,实际上是通过向底层云平台申请创建一个负载均衡器来向外暴露服务;由于 LoadBlancer Service 深度结合了云平台,所以只能在一些云平台上来使用
Ingress
Ingress资源对象,用于将不同URL的访问请求转发到后端不同的Service,以实现HTTP层的业务路由机制。Kubernetes使用一个Ingress策略定义和一个具体的Ingress Controller,两者结合并实现了一个完整的Ingress负载均衡器。
Ingress Controller将基于Ingress规则将客户请求直接转发到Service对应的后端Endpoint上,这样会跳过kube-proxy的转发功能,kube-proxy 不再起作用。
ingress由两部分组成:
在定义Ingress策略之前,需要先部署Ingress Controller,以实现为所有后端Service提供一个统一的入口。Ingress Controller需要实现基于不同HTTP URL向后转发的负载分发机制,并可以灵活设置7层的负载分发策略。如果公有云服务商提供该类型的HTTP路由LoadBalancer,则可以设置其为Ingress Controller.
在Kubernetes中,Ingress Controller将以Pod的形式运行,监控apiserver的/ingress端口后的backend services, 如果service发生变化,则Ingress Controller 应用自动更新其转发规则
我们选择v1.8.0版本
[root@master1 ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.0/deploy/static/provider/baremetal/deploy.yaml -O ingress-nginx-deploy.yaml
cat ingress-nginx-deploy.yaml
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
name: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- endpoints
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- coordination.k8s.io
resourceNames:
- ingress-nginx-leader
resources:
- leases
verbs:
- get
- update
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- networking.k8s.io
resources:
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx
subjects:
- kind: ServiceAccount
name: ingress-nginx
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
name: ingress-nginx-admission
namespace: ingress-nginx
---
apiVersion: v1
data:
allow-snippet-annotations: "true"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-controller
namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-controller-admission
namespace: ingress-nginx
spec:
ports:
- appProtocol: https
name: https-webhook
port: 443
targetPort: webhook
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
minReadySeconds: 0
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
spec:
containers:
- args:
- /nginx-ingress-controller
- --election-id=ingress-nginx-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
image: registry.k8s.io/ingress-nginx/controller:v1.8.0@sha256:744ae2afd433a395eeb13dc03d3313facba92e96ad71d9feaafc85925493fee3
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: controller
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
- containerPort: 8443
name: webhook
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
requests:
cpu: 100m
memory: 90Mi
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
runAsUser: 101
volumeMounts:
- mountPath: /usr/local/certificates/
name: webhook-cert
readOnly: true
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission-create
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission-create
spec:
containers:
- args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407@sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b
imagePullPolicy: IfNotPresent
name: create
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission-patch
namespace: ingress-nginx
spec:
template:
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission-patch
spec:
containers:
- args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407@sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b
imagePullPolicy: IfNotPresent
name: patch
securityContext:
allowPrivilegeEscalation: false
nodeSelector:
kubernetes.io/os: linux
restartPolicy: OnFailure
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 2000
serviceAccountName: ingress-nginx-admission
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: nginx
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
labels:
app.kubernetes.io/component: admission-webhook
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: ingress-nginx-controller-admission
namespace: ingress-nginx
path: /networking/v1/ingresses
failurePolicy: Fail
matchPolicy: Equivalent
name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- networking.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- ingresses
sideEffects: None
#修改其中一部分
[root@master1 ~]# vim ingress-nginx-deploy.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.8.0
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
nodePort: 30080
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
nodePort: 30443
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: NodePort
---
#查看镜像地址
[root@master1 ~]# grep image: ingress-nginx-deploy.yaml
image: registry.k8s.io/ingress-nginx/controller:v1.8.0@sha256:744ae2afd433a395eeb13dc03d3313facba92e96ad71d9feaafc85925493fee3
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407@sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b
image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407@sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b
[root@master1 ~]#
#在线安装修改镜像地址如下,不然无法拉取
registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.8.0
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v20230407
#在线安装修改如下
[root@master1 ~]# grep image: ingress-nginx-deploy.yaml
image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.8.0
image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v20230407
image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v20230407
#离线安装,上传准备好的镜像
[root@docker-registry ~]# docker load -i nginx-ingress-controller_v1.8.0.tar
[root@docker-registry ~]# docker tag ea299dd31352 192.168.1.9:5000/nginx-ingress-controller:v1.8.0
[root@docker-registry ~]# docker push 192.168.1.9:5000/nginx-ingress-controller:v1.8.0
[root@docker-registry ~]# docker load -i kube-webhook-certgen_v20230407.tar
[root@docker-registry ~]# docker tag 7e7451bb7042 192.168.1.9:5000/kube-webhook-certgen:v20230407
[root@docker-registry ~]# docker push 192.168.1.9:5000/kube-webhook-certgen:v20230407
#修改后
[root@master1 ~]# grep image: deploy.yaml
image: 192.168.1.9:5000/controller:v1.8.0
image: 192.168.1.9:5000/kube-webhook-certgen:v20230407
image: 192.168.1.9:5000/kube-webhook-certgen:v20230407
#部署 ingress控制器
[root@master1 ~]# kubectl apply -f ingress-nginx-deploy.yaml
#查看 ingress-nginx-controller pod
[root@master1 ~]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-vd8zr 0/1 Completed 0 24s
ingress-nginx-admission-patch-f26w8 0/1 Completed 0 24s
ingress-nginx-controller-7d6bc9fff-tcxmj 1/1 Running 0 24s
#查看svc
[root@master1 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.96.196.189 <none> 80:30080/TCP,443:30443/TCP 82s
ingress-nginx-controller-admission ClusterIP 10.96.255.10 <none> 443/TCP 82s
[root@master1 ~]# kubectl get all -A | grep ingress
ingress-nginx pod/ingress-nginx-admission-create-vd8zr 0/1 Completed 0 106s
ingress-nginx pod/ingress-nginx-admission-patch-f26w8 0/1 Completed 0 106s
ingress-nginx pod/ingress-nginx-controller-7d6bc9fff-tcxmj 1/1 Running 0 106s
ingress-nginx service/ingress-nginx-controller NodePort 10.96.196.189 <none> 80:30080/TCP,443:30443/TCP 107s
ingress-nginx service/ingress-nginx-controller-admission ClusterIP 10.96.255.10 <none> 443/TCP 107s
ingress-nginx deployment.apps/ingress-nginx-controller 1/1 1 1 107s
ingress-nginx replicaset.apps/ingress-nginx-controller-7d6bc9fff 1 1 1 106s
ingress-nginx job.batch/ingress-nginx-admission-create 1/1 4s 106s
ingress-nginx job.batch/ingress-nginx-admission-patch 1/1 18s 106s
创建一个yaml文件,部署 一个资源,服务,ingress,应用进行验证
cat > nginx-app.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: 192.168.1.9:5000/nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
spec:
ingressClassName: "nginx"
rules:
- host: mrloam.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: nginx-service
port:
number: 80
部署应用
#镜像仓库准备好nginx镜像
[root@docker-registry ~]# docker pull nginx
[root@docker-registry ~]# docker tag 605c77e624dd 192.168.1.9:5000/nginx:latest
[root@docker-registry ~]# docker push 192.168.1.9:5000/nginx:latest
#部署
[root@master1 ~]# kubectl apply -f nginx-app.yaml
#等待创建完成,查看如下
[root@master1 ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-ingress nginx mrloam.com 192.168.1.22 80 15m
验证
[root@master1 ~]# cat >> /etc/hosts << EOF
192.168.1.22 mrloam.com
EOF
[root@master1 ~]# curl mrloam.com:30080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
#新增C:\Windows\System32\drivers\etc
192.168.1.21 mrloam.com
#或者填写成 192.168.1.22 mrloam.com 或 192.168.1.23 mrloam.com ,都是可以访问的
浏览器访问