1. kubernetes基础
1.1 K8S简介
kubernetes 的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:
- 自我修复:一旦某一个容器崩溃,能够在1秒中左右迅速启动新的容器。
- 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整。
- 服务发现:服务可以通过自动发现的形式找到它所依赖的服务。
- 负载均衡:如果一个服务起动了多个容器,能够自动实现请求的负载均衡。
- 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本。
-
1.2 K8S组件
一个 kubernetes 集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件。
master:集群的控制平面,负责集群的决策( 管理 )。
- ApiServer : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API 注册和发现等机制。
- Scheduler : 负责集群资源调度,按照预定的调度策略将 Pod 调度到相应的 node 节点上。
- ControllerManager : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等。
- Etcd :负责存储集群中各种资源对象的信息。
- node:集群的数据平面,负责为容器提供运行环境 ( 干活 )。
- Kubelet : 负责维护容器的生命周期,即通过控制 docker,来创建、更新、销毁容器。
- KubeProxy : 负责提供集群内部的服务发现和负载均衡。
- Docker : 负责节点上容器的各种操作。
组件图示例:
下面,以部署一个 nginx 服务来说明 kubernetes 系统各个组件调用关系:
- 首先要明确,一旦 kubernetes 环境启动之后,master 和 node 都会将自身的信息存储到 etcd 数据库中。
- 一个 nginx 服务的安装请求会首先被发送到 master 节点的 apiServer 组件。
- apiServer 组件会调用 scheduler 组件来决定到底应该把这个服务安装到哪个 node 节点上,在此时,它会从 etcd 中读取各个 node 节点的信息,然后按照一定的算法进行选择,并将结果告知 apiServer。
- apiServer 通过 controller-manager 去调度 Node 节点安装 nginx 服务。
- kubelet 接收到指令后,会通知 docker,然后由 docker 来启动一个 nginx 的 pod。pod 是 kubernetes 的最小操作单元,容器必须跑在 pod 中至此。
- 一个 nginx 服务就运行了,如果需要访问 nginx,就需要通过 kube-proxy 来对 pod 产生访问的代理,这样,外界用户就可以访问集群中的 nginx 服务了。
1.3 K8S概念
- Master:集群控制节点,每个集群需要至少一个 master 节点负责集群的管控。
- Node:工作负载节点,由 master 分配容器到这些 node 工作节点上,然后 node 节点上的 docker 负责容器的运行。
- Pod:kubernetes 的最小控制单元,容器都是运行在 pod 中的,一个 pod 中可以有1个或者多个容器Controller(控制器),通过它来实现对 pod 的管理,比如启动 pod、停止 pod、伸缩 pod 的数量等等。
- Service:pod 对外服务的统一入口,可以维护者同一类的多个 pod。
- Label:标签,用于对 pod 进行分类,同一类 pod 会拥有相同的标签。
- NameSpace:命名空间,用来隔离 pod 的运行环境。
2. K8S集群搭建
2.1 搭建方式
- Kubeadm:是一个 K8s 部署工具,提供 kubeadm init 和 kubeadm join,用于快速部署 Kubernetes 集群。
- 二进制包:从 github 下载发行版的二进制包,手动部署每个组件,组成 Kubernetes 集群。Kubeadm 降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易可控,推荐使用二进制包部署 Kubernetes 集群,虽然手动部署麻烦点,期间可以学习很多工作原理,也利于后期维护。
2.2 准备环境
- 3 台 Centos8.2 服务器,2GB 及其更多 RAM,至少 2 个 CPU,硬盘 30GB 或更多。
- 集群中所有机器之间网络互通,并且可以访问外网,需要拉取镜像。
- 禁用 selinux,关闭防火墙。
- 禁止 swap 分区。
服务器分配如下:
角色 | IP地址 | 组件 |
---|---|---|
k8s-master01 | 192.168.58.21 | docker,kubectl,kubeadm,kubelet |
k8s-node01 | 192.168.58.22 | docker,kubectl,kubeadm,kubelet |
k8s-node02 | 192.168.58.23 | docker,kubectl,kubeadm,kubelet |
部署过程如下:
- 在所有节点上安装 Docker 和 kubeadm。
- 部署 Kubernetes Master。
- 部署容器网络插件。
- 部署 Kubernetes Node,将节点加入Kubernetes 集群中。
- 部署 Dashboard Web 页面,可视化查看 Kubernetes 资源。
2.3 系统初始化
2.3.1 设置系统主机名以及 Host 文件的相互解析(所有节点都要操作)
1、设置系统主机名。
2、配置 hosts 文件。hostnamectl set-hostname k8s-master01 && bash
hostnamectl set-hostname k8s-node01 && bash
hostnamectl set-hostname k8s-node02 && bash
cat <<EOF>> /etc/hosts
192.168.58.21 k8s-master01
192.168.58.22 k8s-node01
192.168.58.23 k8s-node02
EOF
2.3.2 设置防火墙为 Iptables 并设置空规则(所有节点都要操作)
systemctl stop firewalld && systemctl disable firewalld yum -y install iptables-services && systemctl start iptables && systemctl enable iptables && iptables -F && service iptables save
2.3.3 关闭SELINUX(所有节点都要操作)和SWAP分区
# 关闭子文件系统
sudo setenforce 0
sudo sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
# 永久关闭swap
sed -i 's/.*swap.*/#&/' /etc/fstab
swapoff -a
cat /etc/fstab
/dev/mapper/cl-root / xfs defaults 0 0
UUID=77199cf8-27ff-40ce-99e1-f47a652474d2 /boot ext4 defaults 1 2
#/dev/mapper/cl-swap swap swap defaults 0 0
2.3.4 将桥接的 IPv4 流量传递到 iptables 的链
cat <<EOF>> /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system # 生效
2.3.5 kube-proxy开启ipvs的前置条件(所有节点都要操作)
cat <<EOF> /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4
2.3.6 调整内核参数,对于 K8S(所有节点都要操作)
modprobe br_netfilter
cat <<EOF> kubernetes.conf
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0 # 禁止使用 swap 空间,只有当系统 OOM 时才允许使用它
vm.overcommit_memory=1 # 不检查物理内存是否够用
vm.panic_on_oom=0 # 开启 OOM
fs.inotify.max_user_instances=8192
fs.inotify.max_user_watches=1048576
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720
EOF
cp kubernetes.conf /etc/sysctl.d/kubernetes.conf
sysctl -p /etc/sysctl.d/kubernetes.conf
2.3.7 安装所需文件(所有节点都要操作)
1、Centos7 系统使用下列命令安装:
yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget vim net-tools git
2、如果系统是 Centos8,则原有的时间同步服务 ntp/ntpdate 服务已经无法使用,需要安装 chrony
dnf install -y chrony
# 开启并设置为自启动
sudo systemctl start chronyd
sudo systemctl enable chronyd
3、修改 chrony 服务的配置文件,进行时间同步。
- master 节点配置: ```shell vi /etc/chrony.conf
要请求的时间服务器
pool 2.centos.pool.ntp.org iburst (这一行注释掉,增加以下两行)
server ntp.aliyun.com iburst server cn.ntp.org.cn iburst
设置允许请求的服务器网段
allow 192.168.58.2/24
重启chrony服务
systemctl restart chronyd.service chronyc sources -v
- node 节点配置:
```shell
vi /etc/chrony.conf
# 添加要同步的时间服务器
#pool 2.centos.pool.ntp.org iburst
pool 192.168.58.21 iburst
# 重启chrony服务
systemctl restart chronyd.service
chronyc sources -v
2.3.8 调整系统时区(所有节点都要操作)
# 设置系统时区为 中国/上海
timedatectl set-timezone Asia/Shanghai
# 将当前的 UTC 时间写入硬件时钟
timedatectl set-local-rtc 0
# 重启依赖于系统时间的服务
systemctl restart rsyslog
systemctl restart crond
2.3.9 设置 rsyslogd 和 systemd journald(所有节点都要操作)
# 持久化保存日志的目录
mkdir /var/log/journal
mkdir /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF
[Journal]
# 持久化保存到磁盘
Storage=persistent
# 压缩历史日志
Compress=yes
SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=1000
# 最大占用空间 10G
SystemMaxUse=10G
# 单日志文件最大 200M
SystemMaxFileSize=200M
# 日志保存时间 2 周
MaxRetentionSec=2week
# 不将日志转发到 syslog
ForwardToSyslog=no
EOF
systemctl restart systemd-journald
2.3.10 安装 Docker 软件(所有节点都要操作)
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce
## 创建 /etc/docker 目录
mkdir /etc/docker
sudo sh -c 'mkdir -p /etc/docker&&cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-level":"debug",
"debug" : true,
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
],
"experimental" : true
}
EOF'
mkdir -p /etc/systemd/system/docker.service.d
# 重启docker服务
systemctl daemon-reload && systemctl restart docker && systemctl enable docker
# 将k8s加入docker组
usermod -aG docker k8s
上传文件到/etc/yum.repos.d/
目录下,也可以 代替 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
命令。
docker-ce.repo:
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
[docker-ce-stable-debuginfo]
name=Docker CE Stable - Debuginfo $basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/debug-$basearch/stable
enabled=0
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
[docker-ce-stable-source]
name=Docker CE Stable - Sources
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/source/stable
enabled=0
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
[docker-ce-test]
name=Docker CE Test - $basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/test
enabled=0
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
[docker-ce-test-debuginfo]
name=Docker CE Test - Debuginfo $basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/debug-$basearch/test
enabled=0
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
[docker-ce-test-source]
name=Docker CE Test - Sources
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/source/test
enabled=0
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
[docker-ce-nightly]
name=Docker CE Nightly - $basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/nightly
enabled=0
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
[docker-ce-nightly-debuginfo]
name=Docker CE Nightly - Debuginfo $basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/debug-$basearch/nightly
enabled=0
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
[docker-ce-nightly-source]
name=Docker CE Nightly - Sources
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/source/nightly
enabled=0
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
2.3.11 安装Kubeadm(所有节点都要操作)
1、Centos7 安装执行下列命令:
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
yum install -y kubelet kubeadm kubectl && systemctl enable kubelet
2、Centos8 安装执行下列命令:
vi /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
# 安装kubeadm、kubectl、kubelet
yum install -y kubelet kubeadm kubectl
# 启动kubelet服务
systemctl enable kubelet
systemctl start kubelet
# 查看kubectl、kubelet、kubeadm 安装版本
[k8s@localrepo ~]$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.1", GitCommit:"86ec240af8cbd1b60bcc4c03c20da9b98005b92e", GitTreeState:"clean", BuildDate:"2021-12-16T11:39:51Z", GoVersion:"go1.17.5", Compiler:"gc", Platform:"linux/amd64"}
[k8s@localrepo ~]$ kubectl version --client
Client Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.1", GitCommit:"86ec240af8cbd1b60bcc4c03c20da9b98005b92e", GitTreeState:"clean", BuildDate:"2021-12-16T11:41:01Z", GoVersion:"go1.17.5", Compiler:"gc", Platform:"linux/amd64"}
[k8s@localrepo ~]$ kubelet --version
Kubernetes v1.23.1
2.4 部署Kubernetes Master
2.4.1 初始化主节点(主节点操作)
sudo kubeadm init \
--apiserver-advertise-address=192.168.58.21 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.23.1 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
-----------------------------------------------init结果-----------------------------------------------------
kubeadm join 192.168.58.21:6443 --token khxw0u.ruqmjqzowm9lzkjf \
--discovery-token-ca-cert-hash sha256:87ddf4da2d05bdc87beea6b3131a340bb6f416865ff5a0dc3f2c99baa8485c49
------------------------------------------------------------------------------------------------------------
sudo mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
#执行下面命令,使kubectl可以自动补充
source <(kubectl completion bash)
# 查看节点
[k8s@k8s-master01 kubeadm]$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane,master 47s v1.23.1
# 查看pod
[k8s@k8s-master01 kubeadm]$ kubectl get pod --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-6d8c4cb4d-mdjst 0/1 Pending 0 52s
kube-system coredns-6d8c4cb4d-ppg8x 0/1 Pending 0 52s
kube-system etcd-k8s-master01 1/1 Running 0 66s
kube-system kube-apiserver-k8s-master01 1/1 Running 0 68s
kube-system kube-controller-manager-k8s-master01 1/1 Running 0 67s
kube-system kube-proxy-d8s26 1/1 Running 0 52s
kube-system kube-scheduler-k8s-master01 1/1 Running 0 68s
# node节点为NotReady,因为corednspod没有启动,缺少网络pod
2.4.2 加入主节点以及其余工作节点
在其他节点服务器执行下列命令:
kubeadm join 192.168.58.21:6443 --token khxw0u.ruqmjqzowm9lzkjf \
--discovery-token-ca-cert-hash sha256:87ddf4da2d05bdc87beea6b3131a340bb6f416865ff5a0dc3f2c99baa8485c49
# 查看节点
[root@k8s-master01 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 NotReady control-plane,master 115s v1.23.1
k8s-node01 NotReady <none> 17s v1.23.1
k8s-node02 NotReady <none> 14s v1.23.1
2.4.3 安装calco网络
wget https://docs.projectcalico.org/manifests/calico.yaml
# 编辑并修改内容如下:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: calico-kube-controllers
# 使配置生效
kubectl apply -f calico.yaml
# 重新查看集群
[root@k8s-master01 kubeadm]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready control-plane,master 24m v1.23.1
k8s-node01 Ready <none> 22m v1.23.1
k8s-node02 Ready <none> 22m v1.23.1
截止到这里,一个 master + 2node 的集群已经部署完毕,可以正常使用了
2.4.4 部署dashboard界面化管理
1、安装组件,这里无法下载,打开 url 到网页复制到服务器。
# 以下几种方式都可以
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc7/aio/deploy/recommended.yaml
2、修改 recommended.yaml 配置文件。
官方部署 dashboard 的服务没使用 nodeport,将 yaml 文件下载到本地,在 service 里添加 nodeport。
kind: Service
apiVersion: v1
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
type: NodePort
ports:
- port: 443
targetPort: 8443
nodePort: 30000
selector:
k8s-app: kubernetes-dashboard
3、使配置生效:kubectl apply -f recommended.yaml
。
4、查看 pod 和 service。
[root@k8s-master01 kubeadm]# kubectl get svc -n kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.107.194.108 <none> 8000/TCP 21s
kubernetes-dashboard NodePort 10.107.132.109 <none> 443:30000/TCP 21s
5、通过页面访问:https://192.168.58.21:30000/#/login。
6、注册 token 并使用 token 登录。
# 需要使用token登录
# 1、创建token
kubectl create sa dashboard-admin -n kube-system
# 2、授权token 访问权限
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
# 3、取token
ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk '{print $1}')
# 4、获取dashboard.kubeconfig 使用token值
DASHBOARD_LOGIN_TOKEN=$(kubectl describe secret -n kube-system ${ADMIN_SECRET} | grep -E '^token' | awk '{print $2}')
echo ${DASHBOARD_LOGIN_TOKEN}
# 5、使用token登录
eyJhbGciOiJSUzI1NiIsImtpZCI6IjJFU1RUb2IxOHJEajg5U1pvWE1SdVltc1RHeEJxTDNubXBXX2hCa1NSeGsifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4tYnBnZmQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZjMyZTY5YjUtYjc4YS00MThkLWJhMjEtMGE0MzgxMjZhNTgwIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.Vg76-ax8rO66cK7O3J2p4f8-NVDDI0Uw0qvjRiFAgVGsSJS2Oc_OYAUk6AVKXnM9O1yXlnab6OEu-H2Ib2HoMrKpHBfDD42blLzP9DrX3N9kavkI-b6nBrcF4bOgmTEAwZXKfTwV2jvfgdCqDxZtgFknQFUihTg4G2fTNuxoEAaVE1pEGCnF5_SqfQABPlzmw93GY8elVWE29Lp6YobuQpl8lwOgn9_beVuBpqTSN9w0GTuwFWyssMIjQt0hEk-bXgScd-Nw_2RfV0B85Jct9cch1jirOFjG1y1nHca5XEvHSQIUNx-QN7NB9Wff94x5Vb35iuM9zY15qkFjsVYI5g
# 6、注意事项
#kubeadm token 默认时间是24 小时,过期记得从新生成token 然后加入节点
# 查看token
kubeadm token list
# 创建token
kubeadm token create
#忘记初始master节点时的node节点加入集群命令怎么办
# 简单方法
kubeadm token create --print-join-command
# 第二种方法
token=$(kubeadm token generate)
kubeadm token create $token --print-join-command --ttl=0
# 接下来就可以部署监控,应用等。
2.5 测试Kubernetes集群
在 Kubernetes 集群中创建一个 pod,验证是否正常运行:
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc
在页面中进行查看: