1. 安装环境准备

1.1 服务器分配

多 master 方式

主机名 ip地址 角色
localrepo.io 192.168.58.20 localrepo
k8s-master01 192.168.58.21 master
k8s-master02 192.168.58.22 master
k8s-master03 192.168.58.23 master
k8s-node01 192.168.58.24 node
k8s-vip 192.168.58.25 vip
harbor01.io 192.168.58.26 harbor

单 master 方式

主机名 ip地址 角色
localrepo.io 192.168.58.20 localrepo
k8s-master01 192.168.58.21 master
k8s-master02 192.168.58.22 node
k8s-master03 192.168.58.23 node
harbor01.io 192.168.58.26 harbor

1.2 具体步骤

1、设置主机名和 hosts 文件。

  1. sudo hostnamectl set-hostname k8s-vip
  2. # vi /etc/hosts,这里本地库是82端口,harbor库是80端口
  3. 192.168.58.20 localrepo.io
  4. 192.168.58.21 k8s-master01
  5. 192.168.58.22 k8s-master02
  6. 192.168.58.23 k8s-master03
  7. 192.168.58.24 k8s-node01
  8. 192.168.58.25 k8s-vip
  9. 192.168.58.26 harbor01.io

2、设置 SSH 免密登录(可选)。

# 第 1 个节点执行以下命令,默认回车直到结束
ssh-keygen -t rsa
# 将秘钥同步至其他节点
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.58.21
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.58.22
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.58.23
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.58.24
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.58.25
# 免密登录测试
ssh <OTHER_IP/OTHER_HOSTNAME>

3、将服务器时间同步,并设置开机启动同步时间服务。

# 查看服务状态
sudo systemctl status chronyd
# 若服务未启动,则启动并设为开机启动
sudo systemctl enable --now chronyd

# 服务器配置 /etc/chrony.conf
server 192.168.58.20 iburst
bindaddress 192.168.58.20
allow 192.168.58.0/24

# 客户端配置
server 192.168.58.20 iburst

# 重启服务
sudo systemctl restart chronyd.service

4、配置启动时加载 overlay、br_netfilter。

# 检查是否已加载 overlay、br_netfilter 模块,如果您未看到任何结果,则说明未加载
sudo lsmod | grep overlay
# 配置启动时加载
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter

5、修改内核参数,开启 IP 转发功能。

cat <<EOF | sudo tee /etc/sysctl.d/netconf.conf
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
EOF
sudo sysctl --system

6、关闭防火墙和 selinux。

sudo firewall-cmd --state
sudo systemctl stop firewalld.service 
sudo systemctl disable firewalld.service

sudo setenforce 0
sudo sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

7、关闭 swap。

sudo swapoff -a
sudo cp /etc/fstab /etc/fstab_bak
sudo sh -c 'cat /etc/fstab_bak | grep -v swap > /etc/fstab'

8、安装 nfs-utils。

sudo dnf install -y device-mapper-persistent-data lvm2 nfs-utils net-tools

9、若要配置 k8s 使用 IPVS 模式,需进行如下设置。

# 配置启动时加载 IPVS
sudo sh -c 'cat > /etc/sysconfig/modules/ipvs.modules <<EOF
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF'
sudo chmod 755 /etc/sysconfig/modules/ipvs.modules 
sudo bash /etc/sysconfig/modules/ipvs.modules 
# 查看是否已经正确加载所需的内核模块
lsmod | grep -e ip_vs -e nf_conntrack_ipv4
# 安装 ipset 和 ipvsadm
sudo dnf -y install ipset ipvsadm

2. 安装HAProxy

在搭建生产环境的 k8s 集群时,一般需要至少 3 个 master 节点,一旦某个 master 节点发生故障,可以保证随时切换到其他 master 节点使用。但是集群对外的访问接口不可能将多个 apiserver 都暴露出去,并且还要保证在其中一个 apiserver 发生故障时,集群可以自动切换到其他可用节点继续服务,官方的建议是“使用负载均衡器将 apiserver 暴露给工作节点”。因此,我们引入了负载均衡软件 HAProxy 来解决这个问题。

HAProxy 是一个免费的负载均衡软件,可以运行于大部分 Linux 系统上,它基于 TCP 和 HTTP 代理方式,提供高可用的负载均衡,支持健康检查、会话保持、SSL 解析、HTTP 请求重写和重定向等功能,也提供了基于 Web 的统计信息页面以展示健康状态和流量数据。HAProxy 大量利用了操作系统的特性,85%的操作都是在内核层完成,这使得它具有极高的性能,可以支持数以万计的并发连接,并且特别稳定。一般建议 HAProxy 软件独占一台主机,确保 HAProxy 独占资源,避免其他应用引发操作系统或主机的故障;并且至少为 HAProxy 配备一台备机,以应对主机硬件故障等突发情况。

注意:本文档中 HAProxy 是复用 k8s 集群 master 节点的 3 台机器,故 haproxy 监听的端口需要与 kube-apiserver 的端口 6443 不同,避免冲突。
1、安装 haproxy:**sudo dnf -y install haproxy**
2、配置 haproxy。

sudo sh -c 'cat > /etc/haproxy/haproxy.cfg <<EOF #---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
 daemon
 maxconn 3000
 log 127.0.0.1 local2
 pidfile /var/run/haproxy.pid
 stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the listen and backend 
# sections will use if not designated in their block
#---------------------------------------------------------------------
defaults
 mode http
 log global
 option httplog
 option dontlognull
 option http-server-close
 option forwardfor except 127.0.0.0/8
 option redispatch
 retries 3
 timeout http-request 10s
 timeout queue 1m
 timeout connect 10s
 timeout client 1m
 timeout server 1m
 timeout http-keep-alive 10s
 timeout check 10s
 maxconn 3000
#---------------------------------------------------------------------
# apiserver 配置
#---------------------------------------------------------------------
listen apiserver
 mode tcp
 bind *:9443
 balance roundrobin
 server k8s-master01 192.168.58.21:6443 check
 server k8s-master02 192.168.58.22:6443 check
 server k8s-master03 192.168.58.23:6443 check
#---------------------------------------------------------------------
# 监控界面配置
#---------------------------------------------------------------------
listen stats
 bind *:80
 stats enable
 stats uri /stats
 stats refresh 30s
 stats hide-version
 stats auth admin:admin
EOF'

3、启动 haproxy 服务,并设为开机启动。

sudo systemctl enable --now haproxy

4、检测服务,可以看到 haproxy 服务监听的端口。

ss -lnt | grep -E "80|9443"

5、haproxy 服务管理。

sudo systemctl status haproxy
sudo systemctl start haproxy
sudo systemctl stop haproxy
sudo systemctl restart haproxy

3. 安装keepalived

为解决在 k8s 生产环境中多个 master 的访问问题,我们引入了负载均衡软件 HAProxy,这样只要访问 HAProxy 的 IP,它就会将请求自动按照配置的负载均衡策略分发到后端指定的 apiserver 上。但随之而来的一个问题就是 HAProxy 的单点问题,即使我们配置了 HAProxy 备机,也要考虑在 HAProxy 主机出问题时能自动切换到备机的能力,且要求访问的 IP 不变。为了解决这个问题,我们可以采用 keepalived 来实现。

Keepalived 是基于 VRRP (虚拟路由冗余协议) 的一款高可用软件,包括一个 MASTER 和多个 BACKUP。 MASTER 劫持 VIP (虚拟 IP) 对外提供服务,同时 MASTER 会发送组播,BACKUP 收不到 vrrp 包时认为 MASTER 宕机,此时选出剩余优先级最高的节点作为新的 MASTER,并劫持 VIP 提供服务。keepalived 是保证高可用的重要组件。下面在所有安装 HAProxy 的主机上安装 keepalived 软件。
1、安装 keepalived:**sudo dnf -y install keepalived**
2、keepalived 配置。注意 keepalived 的 MASTER 节点与 BACKUP 节点配置的区别(节点角色、节点默认权重)。这里通过配置 keepalived 周期性检查本机 haproxy 进程的状态,如果监测到 haproxy 进程异常,则触发重新选主过程。VIP 将自动漂移到新选出来的主节点,从而实现 VIP 的高可用。

k8s 集群 k8s-master01 主机上 keepalived 的配置

sudo sh -c 'cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
 router_id k8s-master01
 script_user root 
 enable_script_security
}
vrrp_script chk_haproxy {
 script "killall -0 haproxy"
 interval 2
 weight 30 }
vrrp_instance VI_1 {
 state MASTER
 interface ens32
 virtual_router_id 50
 advert_int 1
 priority 80

 authentication {
 auth_type PASS
 auth_pass 1234
 }

 virtual_ipaddress {
 192.168.58.25
 }

 track_script {
 chk_haproxy
 } }
EOF'

k8s 集群 k8s-master02 主机上 keepalived 的配置

sudo sh -c 'cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
 router_id k8s-master02
 script_user root 
 enable_script_security
}
vrrp_script chk_haproxy {
 script "killall -0 haproxy"
 interval 2
 weight 30 }
vrrp_instance VI_1 {
 state BACKUP
 interface ens32
 virtual_router_id 50
 advert_int 1
 priority 70

 authentication {
 auth_type PASS
 auth_pass 1234
 }

 virtual_ipaddress {
 192.168.58.25
 }

 track_script {
 chk_haproxy
 }
}
EOF'

k8s 集群 k8s-master03 主机上 keepalived 的配置

sudo sh -c 'cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
 router_id k8s-master03
 script_user root 
 enable_script_security
}
vrrp_script chk_haproxy {
 script "killall -0 haproxy"
 interval 2
 weight 30 }
vrrp_instance VI_1 {
 state BACKUP
 interface ens32
 virtual_router_id 50
 advert_int 1
 priority 60

 authentication {
 auth_type PASS
 auth_pass 1234
 }

 virtual_ipaddress {
 192.168.58.25
 }

 track_script {
 chk_haproxy
 } }
EOF'

3、启动 keepalived 服务,并设为开机启动。

sudo systemctl enable --now keepalived

4、检测服务,keepalived 的 MASTER 节点获取到了 VIP。

[root@k8s-master01 ~]# ip address show ens32
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:31:82:1d brd ff:ff:ff:ff:ff:ff
    inet 192.168.58.21/24 brd 192.168.58.255 scope global noprefixroute ens32
       valid_lft forever preferred_lft forever
    inet 192.168.58.25/32 scope global ens32
       valid_lft forever preferred_lft forever

5、keepalived 服务管理。

sudo systemctl status keepalived 
sudo systemctl start keepalived 
sudo systemctl stop keepalived 
sudo systemctl restart keepalived

4. 安装containerd

1、在线安装。

sudo sh -c 'cat > /etc/yum.repos.d/Docker-CE.repo <<EOF
[Docker-CE]
name=Docker CE Stable
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF'

sudo dnf install -y https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/containerd.io-1.4.3-3.1.el7.x86_64.rpm

2、离线安装。

sudo dnf install -y http://localrepo.io/Docker-CE/Packages/containerd.io-1.4.3-3.1.el7.x86_64.rpm

3、下载安装 crictl,地址:https://github.com/kubernetes-sigs/cri-tools/releases

tar -xvf crictl-v1.19.0-linux-amd64.tar.gz
sudo mv crictl /usr/local/bin/

4、生成默认配置文件

sudo mkdir -p /etc/containerd
sudo sh -c 'containerd config default > /etc/containerd/config.toml'

5、修改配置文件,使得可以从 harbor 私有仓库 pull 镜像,并使用 systemd 作为 cgroup 驱动,在 /etc/containerd/config.toml 中添加如下内容:

[plugins."io.containerd.grpc.v1.cri"]
 … …
 stream_server_address = "127.0.0.1"
 stream_server_port = "0"
 sandbox_image = "harbor01.io/library/pause:3.2"
… …
 [plugins."io.containerd.grpc.v1.cri".containerd]
 … …
 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
 … …
 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
 SystemdCgroup = true
 … …
 [plugins."io.containerd.grpc.v1.cri".registry]
 [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
 [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor01.io"]
 endpoint = ["https://harbor01.io"]
 [plugins."io.containerd.grpc.v1.cri".registry.configs]
 [plugins."io.containerd.grpc.v1.cri".registry.configs."harbor01.io".tls]
 insecure_skip_verify = true
 [plugins."io.containerd.grpc.v1.cri".registry.configs."harbor01.io".auth]
 username = "admin"
 password = "Harbor12345"

6、检查 containerd 服务,并重启。

cat /usr/lib/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/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=1048576
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target

# 启动服务
sudo systemctl enable --now containerd
systemctl status containerd

systemctl restart containerd

7、配置 crictl。

# 生成配置文件
sudo sh -c 'cat > /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF'

8、验证 containerd 及 crictl 的配置。

# 1、编辑文件 /etc/sudoers,将 Defaults env_reset 改为 Defaults !env_resets
# 2、编辑文件 ~/.bashrc,在文件末尾添加 alias sudo='sudo env PATH=$PATH'
# 3、执行 source ~/.bashrc 生效

#  验证 containerd 及 crictl 的配置
sudo crictl ps

5. 安装k8s

5.1 准备工作

1、在线安装。

sudo sh -c 'cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
 https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF'

2、离线安装,这里注意:需要安装最新版,1.18.6 版本初始化失败。

# 安装最新版本或指定版本的 kubeadm、kubectl、kubelet
sudo dnf install -y kubelet kubectl kubeadm # 安装最新版本
sudo dnf install -y kubelet-1.18.6-0 kubectl-1.18.6-0 kubeadm-1.18.6-0 # 安装指定版本

# 重启 containerd
sudo systemctl restart containerd
# 启动 kubelet,并设为开机自启
#kubelet刚安装后是无法启动的,需要加入节点或者初始化为master后才可以启动
sudo systemctl enable --now kubelet

3、将所需要的 kubeadm 相关镜像下载到本地。

# 查看kubeadm的镜像版本
[root@k8s-master01 yamlconfig]# kubeadm config images list
k8s.gcr.io/kube-apiserver:v1.23.2
k8s.gcr.io/kube-controller-manager:v1.23.2
k8s.gcr.io/kube-scheduler:v1.23.2
k8s.gcr.io/kube-proxy:v1.23.2
k8s.gcr.io/pause:3.6
k8s.gcr.io/etcd:3.5.1-0
k8s.gcr.io/coredns/coredns:v1.8.6

# 拉取镜像,vi kubeadm.sh
#!/bin/bash
set -e
KUBE_VERSION=v1.23.1
KUBE_PAUSE_VERSION=3.6
ETCD_VERSION=3.5.1-0
CORE_DNS_VERSION=1.8.6
GCR_URL=k8s.gcr.io
ALIYUN_URL=registry.cn-hangzhou.aliyuncs.com/google_containers
images=(kube-proxy:${KUBE_VERSION}
kube-scheduler:${KUBE_VERSION}
kube-controller-manager:${KUBE_VERSION}
kube-apiserver:${KUBE_VERSION}
pause:${KUBE_PAUSE_VERSION}
etcd:${ETCD_VERSION}
coredns:${CORE_DNS_VERSION})
for imageName in ${images[@]} ; do
    docker pull $ALIYUN_URL/$imageName
    docker tag  $ALIYUN_URL/$imageName $GCR_URL/$imageName
    docker rmi $ALIYUN_URL/$imageName
done

sh ./kubeadm.sh

4、将 kubeadm 相关镜像上传到 harbor。

# vi kubeadm-push-aliyun.sh

#!/bin/bash
set -e
KUBE_VERSION=v1.23.1
KUBE_PAUSE_VERSION=3.6
ETCD_VERSION=3.5.1-0
CORE_DNS_VERSION=1.8.6
GCR_URL=k8s.gcr.io
ALIYUN_URL=registry.cn-hangzhou.aliyuncs.com/pmk8s #自己的命名空间
images=(kube-proxy:${KUBE_VERSION}
kube-scheduler:${KUBE_VERSION}
kube-controller-manager:${KUBE_VERSION}
kube-apiserver:${KUBE_VERSION}
pause:${KUBE_PAUSE_VERSION}
etcd:${ETCD_VERSION}
coredns:${CORE_DNS_VERSION})
for imageName in ${images[@]} ; do
    docker tag $GCR_URL/$imageName $ALIYUN_URL/$imageName
    docker push $ALIYUN_URL/$imageName
    docker rmi $ALIYUN_URL/$imageName
done

# 任意节点运行脚本
sh ./kubeadm-push-aliyun.sh

5.2 初始化 master 节点。

1、编写初始化文件。

注意: (1)镜像地址默认为 k8s.gcr.io,离线安装使用本地镜像仓库,在线安装可指定阿里云镜像仓库。 (2)podSubnet 为容器组网段,不能与 master/worker 节点所在的网段地址重叠。 (3)若为 k8s 集群为单 master 节点,则 controlPlaneEndpoint 指定为 master 的 IP:6443 即可。若配置了负载均衡,则需指定为 VIP 及相应 Port。 (4)详细配置可参考:https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2

cat > ./kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
nodeRegistration:
 criSocket: /run/containerd/containerd.sock
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.23.1 # 配置镜像仓库地址,离线用 harbor01.io/library,在线用 registry.aliyuncs.com/google_containers
imageRepository: harbor01.io/library
controlPlaneEndpoint: "192.168.58.25:9443"
networking:
 serviceSubnet: "10.96.0.0/16"
 podSubnet: "10.100.0.1/16"
 dnsDomain: "cluster.local"
---
# 指定 Kubelet 的 cgroupDriver
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
---
# 指定 KubeProxy 使用 IPVS 模式
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
EOF

2、执行初始化。若初始化 master 出错可运行 kubeadm reset -f 然后再试。

sudo sh -c 'kubeadm init --config=kubeadm-config.yaml --upload-certs | tee kubeadm-init.log'

# 根据提示为普通用户配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

5.3 安装 calico 网络插件。

(可参考 https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises)

# 在线下载 calico.yaml 文件
curl https://docs.projectcalico.org/manifests/calico.yaml -O 

# 查看镜像
cat calico.yaml | grep image:

# 应用 calico.yaml 文件完成安装,若出错可运行 kubectl delete -f calico.yaml 然后再试
kubectl apply -f calico.yaml

5.4 加入其他节点

1、检查第一个 master 节点初始化结果。

# 查看节点状态
[root@k8s-master01 yamlconfig]# kubectl get nodes -o wide
NAME           STATUS     ROLES                  AGE     VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION          CONTAINER-RUNTIME
k8s-master01   NotReady   control-plane,master   7m32s   v1.23.1   192.168.58.21   <none>        CentOS Linux 8 (Core)   4.18.0-193.el8.x86_64   containerd://1.4.3


# 查看 pod 状态,并等待直到所有的 pod 处于 Running 状态
watch kubectl get pod -n kube-system -o wide

2、将其他 master 节点加入集群(若为单 master 节点,可跳过该步)。

说明:若未记录第一个节点初始化后提示的 kubeadm join 命令,或者在第一个 master 节点初始化完成 2 小时( token 的有效期默认为 2 小时)以后才把一个节点加入 k8s 的控制节点,则可在第一个节点运行以下命令来重新生成 kubeadm join 命令: sudo kubeadm init phase upload-certs —upload-certs | awk ‘END{print “kubeadm token create —print-join-command —certificate-key “ $1}’ | sh -x

# 根据第一个 master 节点初始化完成时提示的命令将当前节点加入控制节点
kubeadm join 192.168.58.25:9443 --token u803di.fnpt2aft0cpr3jw1 \
    --discovery-token-ca-cert-hash sha256:cd54290e2619001f098585827c5722e97fe2b18b58311a8a64b677554160afcd \
    --control-plane --certificate-key 20ab2bae101636eb5b5806e10806ff5fdf64b52cf10b85479fe0ce19366b9bd7

# 同样根据提示为普通用户配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

3、初始化 worker 节点。

说明:若未记录第一个节点初始化后提示的 kubeadm join 命令,或者在第一个 master 节点初始化完成 2 小时( token 的有效期默认为 2 小时)以后才想把一个节点加入 k8s 的集群工作节点,则可在第一个节点运行以下命令来重新生成 kubeadm join 命令: kubeadm token create —print-join-command

# 根据第一个 master 节点初始化完成时提示的命令将当前节点加入集群
kubeadm join 192.168.58.25:9443 --token u803di.fnpt2aft0cpr3jw1 \
    --discovery-token-ca-cert-hash sha256:cd54290e2619001f098585827c5722e97fe2b18b58311a8a64b677554160afcd

4、安装后检查(在 master 节点执行)。

# 查看节点状态信息
kubectl get nodes -o wide

# 查看集群信息
kubectl cluster-info

# 查看所有 pods 的状态
kubectl get pods --all-namespaces -o wide

# 查看 IPVS 是否开启
sudo ipvsadm -Ln
kubectl get pod -n kube-system | grep kube-proxy | awk 'NR==1{print "kubectl logs -n kube-system " $1}' | sh -x

5.5 移除节点

# 删除节点
kubectl delete node node-name

# 加入新节点,在master节点上执行,将输出再到新节点上执行
kubeadm token create --print-join-command

5.6 卸载清理 k8s

kubectl delete node --all
kubeadm reset -f
modprobe -r ipip
rm -rf ~/.kube/
rm -rf /usr/lib/systemd/system/kubelet.service
rm -rf /usr/lib/systemd/system/kubelet.service.d
rm -rf /usr/bin/kube*
rm -rf /etc/sysconfig/kubelet
rm -rf /etc/kubernetes/
rm -rf /etc/cni
rm -rf /var/lib/kubelet
rm -rf /var/lib/etcd
rm -rf /opt/cni

6. 安装Metrics Server

Metrics Server 是 Kubernetes 集群核心监控数据的聚合器,可以通过 Metrics API 的形式获取 Metrics 数据,不过仅仅是获取指标的最新值,不对旧值进行存储,且不负责将指标转发到第三方目标。Metrics Server 还可以与 Kubectl 工具结合使用,提供 kubectl top 命令来展示集群中的指标数据。
1、下载配置文件。

# 在线下载 metrics-server.yaml 文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml -O metrics-server.yaml

wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.0/components.yaml -O metrics-server.yaml

2、 修改 metrics-server.yaml 文件,修正集群问题。

  • 问题 1:metrics-server 默认使用节点 hostname 通过 kubelet 10250 端口获取数据,但是 CoreDNS 里面没有该数据无法解析(10.96.0.10:53),可以通过给 metrics server 启动命令添加参数 —kubelet-preferred-address-types=InternalIP 来指定直接使用节点 IP 地址获取数据。
  • 问题 2:kubelet 的 10250 端口使用的是 https 协议,连接需要验证 tls 证书。可以通过给 metrics server 启动命令添加参数 —kubelet-insecure-tls
  • 来指定不验证客户端证书
  • 问题 3:yaml 文件中的 image 的默认地址为 k8s.gcr.io/metrics-server/metrics-server:v0.3.7,该地址国内不能访问,需要修改。内网离线安装可指定为内网镜像仓库地址 harbor01.io/library/metrics-server:v0.3.7
  • 有一点需要注意,如果 k8s 版本是 1.23.1 的话,需要修改 apiregistration.k8s.io/v1beta1为 apiregistration.k8s.io/v1。
# vi metrics-server.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
 name: metrics-server
 … …
spec:
 … … 
 template:
 spec:
 … …
 containers:
 - name: metrics-server
 #image: k8s.gcr.io/metrics-server/metrics-server:v0.3.7
 image: harbor01.io/library/metrics-server:v0.3.7 # 修改
 imagePullPolicy: IfNotPresent
 args:
 - --cert-dir=/tmp
 - --secure-port=4443
 - --kubelet-insecure-tls # 新增
 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname # 新增

3、 部署 Metrics Server,若出错或需修改可先运行 kubectl delete -f metrics-server.yaml 后再试。

# 应用 metrics-server.yaml 文件进行部署
kubectl apply -f metrics-server.yaml

# 查看是相应 pod 否运行
[root@k8s-master01 yamlconfig]# kubectl get pods --all-namespaces | grep metrics-server
kube-system   metrics-server-5c4d856598-w7xj7            1/1     Running   0               54s

注意:Metrics Server 采集指标需要点时间,因此需要等几分钟再执行以下命令,查看指标信息。若出错,可用以下命令查看日志信息:
kubectl get pods --all-namespaces | grep metrics-server | awk '{print "kubectl logs -n kube-system " $2}' | sh -x

# 通过 kubectl 工具进行测试,获取全部节点指标信息
[root@k8s-master01 yamlconfig]# kubectl top node
NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
k8s-master01   158m         3%     1173Mi          43%       
k8s-master02   120m         3%     918Mi           33%       
k8s-master03   128m         3%     871Mi           32%       
k8s-node01     54m          1%     471Mi           17%       

# 获取全部 Namespace 下的 Pod 的指标信息
[root@k8s-master01 yamlconfig]# kubectl top pods --all-namespaces
NAMESPACE     NAME                                       CPU(cores)   MEMORY(bytes)   
kube-system   calico-kube-controllers-85b5b5888d-gmjk2   4m           39Mi            
kube-system   calico-node-826rm                          32m          143Mi           
kube-system   calico-node-8vxfn                          29m          142Mi       
...

7. K8S图像化界面

7.1 安装Kuboard

Kuboard 为第三方开发的 Kubernetes 的 Web UI,可以替代官方的 Kubernetes Dashboard。二者只需选一个安装即可。
1、下载配置文件。

# 在线下载 kuboard.yaml 文件
curl https://kuboard.cn/install-script/kuboard.yaml -O

2、 修改 kuboard.yaml 文件,检查镜像仓库地址,将 imagePullPolicy 由默认的 Always 改为 IfNotPresent,调整 Nodeport 端口。

apiVersion: apps/v1
kind: Deployment
spec:
 replicas: 1
 ……
 template:
 ……
 spec:
 containers:
 - name: kuboard
 image: harbor01.io/library/kuboard:latest  #修改
 #imagePullPolicy: Always
 imagePullPolicy: IfNotPresent #修改
 tolerations:
 - key: node-role.kubernetes.io/master
 effect: NoSchedule
---
apiVersion: v1
kind: Service
metadata:
 name: kuboard
 namespace: kube-system
spec:
 type: NodePort
 ports:
 - name: http
 port: 80
 targetPort: 80
 nodePort: 32567  #新增
 selector:
 k8s.kuboard.cn/layer: monitor
k8s.kuboard.cn/name: kuboard

3、 应用 kuboard.yaml 文件完成部署。

kubectl apply -f kuboard.yaml 
# 查看 Kuboard 运行状态
kubectl get pods -l k8s.kuboard.cn/name=kuboard -n kube-system

4、 获取 token 用于访问。

您可以获得管理员用户和只读用户的 Token。管理员用户的 Token 拥有 ClusterAdmin 的权限,可以执行所有操作。只读用户的 Token 不能对集群的配置执行修改操作,可查看名称空间的内容、可查看节点信息、可查看存储类和存储卷声明的信息。

# 管理员用户 Token 获取
echo $(kubectl -n kube-system get secret $(kubectl -n kube-system get secret \
| grep kuboard-user | awk '{print $1}') -o go-template='{{.data.token}}' | base64 -d)

# 多master token
eyJhbGciOiJSUzI1NiIsImtpZCI6InRWZm9oY0RfZEhGNEQ2SzFwVV9MQXdralRyVzRhTVlOdTEwMTFqTUotZkUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tcWtmd2IiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3Vib2FyZC11c2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMjNkYjFmYzgtM2MzZS00NmUzLTg4ZDUtODcyMzlkMDY1MGY2Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.pEMAVQc3ux9kQOBiDEKnHJFa4vZLJE58hGJVzPu83a1BG9eK9clnX3VBYSNNNYmokzfvyEb2hkU4C8yDObCzxmhnW5uOPuw_w_7Sun1LKC3Fo0UFbxKwhi76ocXNGVXITD9yjmhA77DyIvdI8R8X2HaESULnU9eAmZFUY-pcGQuI_Oa4rfaRsTEvldRMCf0zRGBJS1JvTaq9_a09mGlOeMvt2OzrbRB1lcjxS9FWuh2iqszrhCC865UqSiq3lujlK5NXeo_MiYGkMA8Aa-zsLwv1hz2KqNl8GybkNEoKiToRCb2-YvX--3mT7zs0pnizCjkeS3_MGXSYHu-YiRKlQQ

# 单master token
eyJhbGciOiJSUzI1NiIsImtpZCI6InFKNW9CV01la0R2V0tzUDNZVnBtWURxeWplT2RYRDduT2Y1X3RHLUhFTnMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tNXA5NXciLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3Vib2FyZC11c2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiN2Y4OWNjZDEtNDk2Ni00ODAxLWJjYTktZWJhNDIyYmE0NjI2Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.NZRQAhwSg-oG85dOm-OV7IPA1FbPw5OiP0XZkOKFy5LTfcX_gpk8nZnLwvHGhM4Crcb2WNFbZ0mDHFsALedge1NTKRyxJfFzbIr8e-y4JyU_efPXFBRA7JJQ_fRi-ha1CoaJaWYbrcydDW4aXCRz7boroKkTLizo_fgyC3QlU381rO6WBKLk9s2rj-PYT5VsFbt_J1aueUvcsA479ER4AkvYRLrR7wtOdGMfx-e46J0X9iYoHo9UfRlUwKzivBGItzO78fCVxJUEmD2T2Yo8W_Or3RO7AAGaRVZ3zmo4FmOfOG-UpQsxCdbrZMZ2gm14KAIwTV9RaPsfVPDP728Lag


# 只读用户 Token 获取
echo $(kubectl -n kube-system get secret $(kubectl -n kube-system get secret \
| grep kuboard-viewer | awk '{print $1}') -o go-template='{{.data.token}}' | base64 -d)

5、 访问 kuboard
Kuboard Service 使用了 NodePort 的方式暴露服务,NodePort 的默认端口为 32567;您可以按如下方式访问 Kuboard:https://192.168.58.21:32567**,**输入前一步骤中获得的 token,即可进入 Kuboard 集群概览页。
6、 免登陆访问
可以通过查询参数中的 k8sToken 字段直接登录系统,无需在登录界面输入 Token。

  • 直接访问集群概览页:http://192.168.58.21:32567/dashboard?k8sToken=yourtoken
  • 直接访问终端界面:http://192.168.58.21:32567/console/yournamespace/yourpod?containerName=yourcontainer&shell=bash&k8sToken=yourtoken

    7.2 安装Kubernetes Dashboard

    省略,之前写的博客有。

    8. Harbor和k8s集成

    8.1 集成说明

    由于 harbor 采用了用户名、密码认证,因此在 k8s 中访问 harbor 需要进行配置,以告知 Pods 使用有效的凭证访问正确的 harbor 服务地址来获取容器镜像。有两种配置方法,一种方法是在每次创建 pod 时都显式使用 ImagePullSecrets 定义获取镜像使用的配置和认证信息;另一种方法是通过 service account 为 k8s 绑定一个全局性的镜像服务配置信息,后续在创建 pod 时会被自动地在资源定义中附加上访问容器镜像资源服务的所需的配置和认证信息。以上两种方法没有优劣之分,各自有适用的场景。前者胜在灵活性,而后者则降低了一点使用上的复杂性。

    8.2 在Pod中指定ImagePullSecrets的方法

    8.2.1 方法一:通过命令行创建 secret

    kubectl create secret docker-registry harbor-secret --namespace=default \
    --docker-server=harbor01.io --docker-username=admin --docker-password=Harbor12345
    

    8.2.2 方法二:通过已有的Docker认证信息创建secret

    1、如果你已经使用 docker login 登录过私有镜像仓库服务了,那么可以直接把这份已有的认证信息拷贝到 Kubernetes 中使用。 ```shell cat ~/.docker/config.json

{ “auths”: { “harbor01.io”: { “auth”: “YWRtaW46SGFyYm9yMTIzNDU=” } } }

2、找到保存了登录私有仓库认证信息的文件,然后使用 base64 编码生成一份不带换行的字符串数据。
```shell
[root@harbor01 ~]# cat ~/.docker/config.json | base64 -w 0
ewoJImF1dGhzIjogewoJCSJoYXJib3IwMS5pbyI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0KfQ==

3、定义一个 secret.yaml 文件,data[“.dockerconfigjson”] 的值需要是以 base64 编码且不带换行的认证信息字符串。

cat > secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
 name: harbor-secret
 namespace: default
data:
 .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJoYXJib3IwMS5pbyI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0KfQ==
type: kubernetes.io/dockerconfigjson
EOF

4、创建 secret。

# 创建 secret
kubectl apply -f secret.yaml
# 查看新创建的 secret
kubectl get secret -n default
kubectl describe secrets harbor-secret -n default
kubectl get secret harbor-secret -o yaml -n default

5、使用私有仓库的私有镜像时在 yaml 文件中指定 imagePullSecrets。

注意:如果你的系统环境中,需要访问多个私有的容器镜像仓库,你可以为每个私有仓库创建一个密钥,然后在 pod 定义文件中同时引用它们。 Kubelet 将会把所有的 imagePullSecrets 合并为一个虚拟的.docker/config.json 后使用。

spec:
 containers:
 - name: <name>
 image: <your-private-image>
imagePullSecrets:
 - name: harbor-secret

8.3 把ImagePullSecrets添加到一个service account的使用方法

1、前面,我们需要在每个 pod 的定义文件中显示指定访问私有镜像仓库服务的密钥信息,使用起来比较繁琐,其实我们还有另外一个选择,就是
把 imagePullSecrets 的配置信息附加到命名空间中的 default 账号(serviceaccount)上去。

kubectl get sa -n default
kubectl describe sa default -n default
kubectl get serviceaccounts default -o yaml -n default
kubectl patch serviceaccount -n default default -p '{"imagePullSecrets": [{"name": "harbor-secret"}]}'

# 再次查看 serviceaccounts,可以看到已经包含了 imagePullSecrets 信息
kubectl get serviceaccounts default -o yaml -n default

2、 在 kubernetes 中删除 secret 的命令

kubectl delete secrets harbor-secret -n default