my kubernetes beginner notes
# Kubernetes 入门笔记
# 前置内容
- Linux | Linux 入门笔记
- Docker | Docker 入门笔记
# 目录
-
1 Kubernetes 概念和架构
-
2 从零搭建 Kubernetes 集群
-
3 Kubernetes 核心概念
-
4 搭建集群监控平台系统
-
5 从零搭建高可用 Kubernetess 集群
-
6 在集群环境中部署项目
# 1 Kubernetes 概述和架构
# 1.1 Kubernetes 简介
Kubernetes,首字母 K,尾字母 s,中间 8 个字母,简称 K8s。
# 1.2 Kubernetes 功能
目前只需要知道 Kubernetes 有以下 9 个功能,关于这 9 个功能,后面详细介绍。(我也不知道这些是啥玩意,先记住名词再说)
-
自动装箱
- 基于容器对应用运行环境的资源配置要求自动部署应用容器
-
自我修复
-
当容器失败时,会对容器进行重启
-
当所部署的 Node 节点有问题时,会对容器进行重新部署和重新调度
-
当容器未通过监控检查时,会关闭此容器直到容器正常运行时,才会对外提供服务
-
-
水平扩展
-
通过简单的命令、用户 UI 界面或基于 CPU 等资源使用情况,对应用容器进行规模扩大或规模剪裁
-
当我们有大量的请求来临时,我们可以增加副本数量,从而达到水平扩展的效果
-
-
服务发现
- 用户不需使用额外的服务发现机制,就能够基于 Kubernetes 自身能力实现服务发现和负载均衡
-
滚动更新
- 可以根据应用的变化,对应用容器运行的应用,进行一次性或批量式更新
-
版本回退
- 可以根据应用部署情况,对应用容器运行的应用,进行历史版本即时回退
-
密钥和配置管理
- 在不需要重新构建镜像的情况下,可以部署和更新密钥和应用配置,类似热部署。
-
存储编排
-
自动实现存储系统挂载及应用,特别对有状态应用实现数据持久化非常重要
-
存储系统可以来自于本地目录、网络存储 (NFS、Gluster、Ceph 等)、公共云存储服务
-
-
批处理
- 提供一次性任务,定时任务;满足批量数据处理和分析的场景
# 1.3 Kubernetes 架构组件
Kuebrnetes 架构图
Kubernetes 架构主要包含两部分:Master(主控节点)和 Work node(工作节点)。
图 1
图 2
图 3
Kubernetes 组件
-
Master:主控节点
- API Server:集群统一入口,以 restful 风格进行操作,同时交给 etcd 存储
- 提供认证、授权、访问控制、API 注册和发现等机制
- scheduler:节点的调度,选择 node 节点应用部署
- controller-manager:处理集群中常规后台任务,一个资源对应一个控制器
- etcd:存储系统,用于保存集群中的相关数据
- API Server:集群统一入口,以 restful 风格进行操作,同时交给 etcd 存储
-
Worker node:工作节点
- Kubelet:master 派到 node 节点代表,管理本机容器
- 一个集群中每个节点上运行的代理,它保证容器都运行在 Pod 中
- 负责维护容器的生命周期,同时也负责 Volume (CSI) 和 网络 (CNI) 的管理
- kube-proxy:提供网络代理,负载均衡等操作
- Kubelet:master 派到 node 节点代表,管理本机容器
-
容器运行环境【Container Runtime】
- 容器运行环境是负责运行容器的软件
- Kubernetes 支持多个容器运行环境:Docker、containerd、cri-o、rktlet 以及任何实现 Kubernetes CRI (容器运行环境接口) 的软件。
-
fluentd:是一个守护进程,它有助于提升集群层面日志
# 1.4 Kubernetes 核心概念
-
Pod
- Pod 是 K8s 中最小的单元
- 一组容器的集合
- 共享网络【一个 Pod 中的所有容器共享同一网络】
- 生命周期是短暂的(服务器重启后,就找不到了)
-
Volume
- 声明在 Pod 容器中可访问的文件目录
- 可以被挂载到 Pod 中一个或多个容器指定路径下
- 支持多种后端存储抽象【本地存储、分布式存储、云存储】
-
Controller
-
确保预期的 pod 副本数量【ReplicaSet】
-
无状态应用部署【Deployment】
- 无状态就是指,不需要依赖于网络或者 ip
-
有状态应用部署【StatefulSet】
- 有状态需要特定的条件
-
确保所有的 node 运行同一个 pod 【DaemonSet】
-
一次性任务和定时任务【Job 和 CronJob】
-
-
Deployment
- 定义一组 Pod 副本数目,版本等
- 通过控制器【Controller】维持 Pod 数目【自动回复失败的 Pod】
- 通过控制器以指定的策略控制版本【滚动升级、回滚等】
-
Service
- 定义一组 pod 的访问规则
- Pod 的负载均衡,提供一个或多个 Pod 的稳定访问地址
- 支持多种方式【ClusterIP、NodePort、LoadBalancer】
-
Label
- label:标签,用于对象资源查询,筛选
-
Namespace
- 命名空间,逻辑隔离
- 一个集群内部的逻辑隔离机制【鉴权、资源】
- 每个资源都属于一个 namespace
- 同一个 namespace 所有资源不能重复
- 不同 namespace 可以资源名重复
-
API
- 我们通过 Kubernetes 的 API 来操作整个集群
- 同时我们可以通过 kubectl 、ui、curl 最终发送 http + json/yaml 方式的请求给 API Server,然后控制整个 K8S 集群,K8S 中所有的资源对象都可以采用 yaml 或 json 格式的文件定义或描述
# 1.5 Kubernetes 工作原理
Kubernetes 工作原理图
能看懂就看,看不懂就算了,俺也看不懂。
# 2 从零开始搭建 K8s 集群
# 2.1 基于客户端工具 kubeadm
kubeadm 是官方社区推出的一个用于快速部署 kubernetes 集群的工具。
这个工具能通过两条指令完成一个 kubernetes 集群的部署:
# 创建一个 Master 节点
kubeadm init
# 将一个 Worker node 节点加入到当前集群中
kubeadm join <Master节点的IP和端口 >
# 2.1.1 安装步骤
使用 kubeadm 方式搭建 Kubernetes 集群主要分为以下几步:
- 【环境准备】准备三台虚拟机,并安装操作系统 CentOS 7.x
- 【系统初始化】对三个刚安装好的操作系统进行初始化操作
- 【安装工具】在三个节点安装
docker
kubelet
kubeadm
kubectl
- 【集群部署 - master】在 master 节点执行
kubeadm init
命令初始化 - 【集群部署 - node】在 node 节点上执行
kubeadm join
命令,把 node 节点添加到当前集群 - 【安装网络插件】配置 CNI 网络插件,用于节点之间的连通
- 【测试集群】通过拉取一个 nginx 进行测试,能否进行外网测试
# 2.1.2 安装要求
在开始之前,部署 Kubernetes 集群机器需要满足以下几个条件:
- 一台或多台机器,操作系统 CentOS7.x-86_x64
- 硬件配置:2GB 或更多 RAM,2 个 CPU 或更多 CPU,硬盘 30GB 或更多【注意】【注意】【注意】【master 需要两核】
- 可以访问外网,需要拉取镜像,如果服务器不能上网,需要提前下载镜像并导入节点
- 禁止 swap 分区
# 2.1.3 准备环境
不会配置环境的可以参考 Linux 入门笔记 | 虚拟机 IP 配置
角色 | IP | 配置 | 操作 |
---|---|---|---|
k8smaster1 | 192.168.60.151 | 2C 2G | init docker kubelet kubeadm kubectl kubeadm init cni |
k8snode1 | 192.168.60.152 | 2C 2G | init docker kubelet kubeadm kubectl kubeadm join |
k8snode2 | 192.168.60.153 | 2C 2G | init docker kubelet kubeadm kubectl kubeadm join |
# 2.1.4 系统初始化
【在每台机器上】执行下面的命令:
# 关闭防火墙
systemctl stop firewalld
# 禁用firewalld服务
systemctl disable firewalld
# 关闭selinux
# 临时关闭【立即生效】告警,不启用,Permissive,查看使用 getenforce 命令
setenforce 0
# 永久关闭【重启生效】
sed -i 's/SELINUX=enforcing/\SELINUX=disabled/' /etc/selinux/config
# 关闭swap
# 临时关闭【立即生效】查看使用 free 命令
swapoff -a
# 永久关闭【重启生效】
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 在主机名静态查询表中添加3台主机
cat >> /etc/hosts << EOF
192.168.60.151 k8smaster
192.168.60.152 k8snode1
192.168.60.153 k8snode2
EOF
# 将桥接的IPv4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
# 使k8s配置生效
sysctl --system
# 时间同步
yum install ntpdate -y
ntpdate time.windows.com
# 根据规划设置主机名【k8smaster1节点上操作】
hostnamectl set-hostname ks8master1
# 根据规划设置主机名【k8snode1节点上操作】
hostnamectl set-hostname k8snode1
# 根据规划设置主机名【k8snode2节点操作】
hostnamectl set-hostname k8snode2
# 2.1.5 安装组件
【所有节点】需要安装以下组件 ,Kubernetes 默认 CRI(容器运行时)为 Docker,因此先安装 Docker。
- Docker
- kubeadm
- kubelet
- kubectl
1、安装 Docker
# 配置一下Docker的yum源【阿里云】
cat >/etc/yum.repos.d/docker.repo<<EOF
[docker-ce-edge]
name=Docker CE Edge - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/\$basearch/edge
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
# 然后yum方式安装docker
yum -y install docker-ce
# 查看docker版本
docker --version
# 配置docker的镜像源【阿里云】
cat >> /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
# 启动docker
systemctl enable docker
systemctl start docker
systemctl status docker
2、安装 kubeadm,kubelet 和 kubectl
# 配置k8s的yum源【阿里云】
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
# 安装kubelet、kubeadm、kubectl,同时指定版本
yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
# 设置开机自启【这里暂时先不启动kubelet】
systemctl enable kubelet
# 2.1.6 集群部署【master 节点】
在 192.168.60.151
上执行【集群初始化命令】,也就是 k8smaster1
节点
kubeadm init --apiserver-advertise-address=192.168.60.151 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.18.0 --service-cidr=10.96.0.0/12 --pod-network-cidr=10.244.0.0/16
由于默认拉取镜像地址 k8s.gcr.io 国内无法访问,这里指定阿里云镜像仓库地址,【执行上述命令会比较慢,因为后台其实已经在拉取镜像了】,我们 docker images 命令即可查看已经拉取的镜像。
部署成功后,【系统提示】运行以下命令使用 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
执行完成后,我们使用下面命令,查看我们正在运行的节点
kubectl get nodes
# 2.1.7 集群部署【node 节点】
下面我们需要到 k8snode1
和 k8snode2
服务器,执行下面的代码向集群添加新节点
执行在 kubeadm init 输出的 kubeadm join 命令:
注意,以下的命令是在 k8smaster1 初始化完成后给出的,每个人的都不一样!!!需要复制自己生成的
kubeadm join 192.168.60.151:6443 --token 8j6ui9.gyr4i156u30y80xf \
--discovery-token-ca-cert-hash sha256:eda1380256a62d8733f4bddf926f148e57cf9d1a3a58fb45dd6e80768af5a500
默认 token 有效期为 24 小时,当过期之后,该 token 就不可用了。这时就需要重新创建 token,操作如下:
kubeadm token create --print-join-command
当我们把两个节点都加入进来后,我们就可以去 k8smaster1
节点下 执行下面命令查看情况
kubectl get nodes
# 2.1.8 部署 CNI 网络插件
上面的状态还是 NotReady,下面我们需要网络插件,来进行联网访问
# 下载网络插件配置
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 添加
kubectl apply -f kube-flannel.yml
# 等一会!
# ......
# 查看状态 【kube-system是k8s中的最小单元】
kubectl get pods -n kube-system
运行后的结果为 Ready 状态
【提示】如果上述操作完成后,还存在某个节点处于 NotReady 状态,可以在 Master 将该节点删除
# 将k8snode1节点删除【在k8smaster1节点上操作】
kubectl delete node k8snode1
# 将k8snode1节点进行重置【在k8snode1节点上操作】
kubeadm reset
# 将k8snode1节点加入集群【在k8snode1节点上操作】
kubeadm join 192.168.60.151:6443 --token 8j6ui9.gyr4i156u30y80xf --discovery-token-ca-cert-hash sha256:eda1380256a62d8733f4bddf926f148e57cf9d1a3a58fb45dd6e80768af5a500
# 2.1.9 测试 kubernetes 集群
我们都知道 K8S 是容器化技术,它可以联网去下载镜像,用容器的方式进行启动
在 Kubernetes 集群中创建一个 pod,验证是否正常运行:
# 下载nginx 【会联网拉取nginx镜像】
kubectl create deployment nginx --image=nginx
# 查看状态
kubectl get pod
如果我们出现 Running 状态的时候,表示已经成功运行了
下面我们就需要将端口暴露出去,让其它外界能够访问
# 暴露端口
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看一下对外的端口
kubectl get pod,svc
我这里,已经成功暴露了 80 端口 到 30529 上
我们到我们的宿主机浏览器上,访问如下地址
http://192.168.60.151:30529/
发现我们的 nginx 已经成功启动了
# 2.1.10 错误汇总
错误一
在执行 Kubernetes init 方法的时候,出现这个问题
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR NumCPU]: the number of available CPUs 1 is less than the required 2
是因为 VMware 设置的核数为 1,而 K8S 需要的最低核数应该是 2,调整核数重启系统即可
错误二
我们在给 k8snode1 节点使用 kubernetes join 命令的时候,出现以下错误
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR Swap]: running with swap on is not supported. Please disable swap
错误原因是我们需要关闭 swap【可能是永久关闭 swap 时没有重启生效】
# 关闭swap
# 临时关闭【立即生效】
swapoff -a
# 永久关闭【重启生效】
sed -ri 's/.*swap.*/#&/' /etc/fstab
错误三
在给 k8snode1 节点使用 kubernetes join 命令的时候,出现以下错误
The HTTP call equal to 'curl -sSL http://localhost:10248/healthz' failed with error: Get http://localhost:10248/healthz: dial tcp [::1]:10248: connect: connection refused
解决方法,首先需要到 k8smaster1 节点,创建一个文件
# 创建文件夹
mkdir /etc/systemd/system/kubelet.service.d
# 创建文件
vim /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
# 添加如下内容
Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true --fail-swap-on=false"
# 重置
kubeadm reset
然后删除刚刚创建的配置目录
rm -rf $HOME/.kube
然后 在 k8smaster1 重新初始化
kubeadm init --apiserver-advertise-address=92.168.60.151:6443 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.18.0 --service-cidr=10.96.0.0/12 --pod-network-cidr=10.244.0.0/16
初始完成后,我们再到 k8snode1 节点,执行 kubeadm join 命令,加入到 k8smaster1【下面这条命令是 k8smaster1 初始化后自动生成的】
kubeadm join 192.168.60.151:6443 --token c7a7ou.z00fzlb01d76r37s \
--discovery-token-ca-cert-hash sha256:9c3f3cc3f726c6ff8bdff14e46b1a856e3b8a4cbbe30cab185f6c5ee453aeea5
添加完成后,我们使用下面命令,查看节点是否成功添加
kubectl get nodes
错误四
我们再执行查看节点的时候, kubectl get nodes 会出现问题
Unable to connect to the server: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "kubernetes")
这是因为我们之前创建的配置文件还存在,也就是这些配置
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
我们需要做的就是把配置文件删除,然后重新执行一下
rm -rf $HOME/.kube
然后再次创建一下即可
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
这个问题主要是因为我们在执行 kubeadm reset 的时候,没有把 $HOME/.kube 给移除掉,再次创建时就会出现问题了
错误五
安装的时候,出现以下错误
Another app is currently holding the yum lock; waiting for it to exit...
是因为 yum 上锁占用,解决方法
yum -y install docker-ce
错误六
在使用下面命令,添加 k8snode1 节点到集群上的时候
kubeadm join 192.168.60.151:6443 --token jkcz0t.3c40t0bqqz5g8wsb --discovery-token-ca-cert-hash sha256:bc494eeab6b7bac64c0861da16084504626e5a95ba7ede7b9c2dc7571ca4c9e5
然后出现了这个错误
[root@k8smaster1 ~]# kubeadm join 192.168.60.151:6443 --token jkcz0t.3c40t0bqqz5g8wsb --discovery-token-ca-cert-hash sha256:bc494eeab6b7bac64c0861da16084504626e5a95ba7ede7b9c2dc7571ca4c9e5
W1117 06:55:11.220907 11230 join.go:346] [preflight] WARNING: JoinControlPane.controlPlane settings will be ignored when control-plane flag is not set.
[preflight] Running pre-flight checks
[WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR FileContent--proc-sys-net-ipv4-ip_forward]: /proc/sys/net/ipv4/ip_forward contents are not set to 1
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher
出于安全考虑,Linux 系统默认是禁止数据包转发的。所谓转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的 ip 地址将包发往本机另一网卡,该网卡根据路由表继续发送数据包。这通常就是路由器所要实现的功能。也就是说 /proc/sys/net/ipv4/ip_forward 文件的值不支持转发
- 0:禁止
- 1:转发
所以我们需要将值修改成 1 即可
echo “1” > /proc/sys/net/ipv4/ip_forward
修改完成后,重新执行命令即可
# 2.2 基于二进制方式
参考资料:https://blog.csdn.net/qq_40942490/article/details/114022294
# 2.2.1 安装步骤
使用二进制包方式搭建 Kubernetes 集群主要分为以下几步:
- 【环境准备】准备三台虚拟机,并安装操作系统 CentOS 7.x
- 【系统初始化】对三个刚安装好的操作系统进行初始化操作
- 【部署 etcd 集群】对三个节点安装 etcd
- 【安装 Docker】对三个节点安装 docker
- 【部署 mastber 组件】在 master 节点上安装
kube-apiserver
、kube-controller-manager
、kube-scheduler
- 【部署 node 组件】在 node 节点上安装
kubelet
、kube-proxy
- 【安装网络插件】配置 CNI 网络插件,用于节点之间的连通
- 【测试集群】通过拉取一个 nginx 进行测试,能否进行外网测试
# 2.1.2 安装要求
在开始之前,部署 Kubernetes 集群机器需要满足以下几个条件:
- 一台或多台机器,操作系统 CentOS7.x-86_x64
- 硬件配置:2GB 或更多 RAM,2 个 CPU 或更多 CPU,硬盘 20GB 或更多【注意】【注意】【注意】【master 需要两核】
- 可以访问外网,需要拉取镜像,如果服务器不能上网,需要提前下载镜像并导入节点
- 禁止 swap 分区
# 2.1.3 准备环境
不会配置环境的可以参考 Linux 入门笔记 | 虚拟机 IP 配置
角色 | IP | 配置 | 操作 |
---|---|---|---|
k8smaster1 | 192.168.60.151 | 2C 2G | init etcd docker kube-apiserver kube-controller-manager kube-scheduler cni |
k8snode1 | 192.168.60.152 | 2C 2G | init etcd docker kubelet kube-proxy |
k8snode2 | 192.168.60.153 | 2C 2G | init etcd docker kubelet kube-proxy |
# 2.2.4 系统初始化
在每台机器上执行下面的命令:
# 关闭防火墙
systemctl stop firewalld
# 禁用firewalld服务
systemctl disable firewalld
# 关闭selinux
# 临时关闭【立即生效】告警,不启用,Permissive,查看使用 getenforce 命令
setenforce 0
# 永久关闭【重启生效】
sed -i 's/SELINUX=enforcing/\SELINUX=disabled/' /etc/selinux/config
# 关闭swap
# 临时关闭【立即生效】查看使用 free 命令
swapoff -a
# 永久关闭【重启生效】
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 在主机名静态查询表中添加3台主机
cat >> /etc/hosts << EOF
192.168.60.151 k8smaster
192.168.60.152 k8snode1
192.168.60.153 k8snode2
EOF
# 将桥接的IPv4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
# 使k8s配置生效
sysctl --system
# 时间同步
yum install ntpdate -y
ntpdate time.windows.com
# 根据规划设置主机名【k8smaster1节点上操作】
hostnamectl set-hostname ks8master1
# 根据规划设置主机名【k8snode1节点上操作】
hostnamectl set-hostname k8snode1
# 根据规划设置主机名【k8snode2节点操作】
hostnamectl set-hostname k8snode2
# 2.2.5 部署 etcd 集群
Etcd 是一个分布式键值存储系统,Kubernetes 使用 Etcd 进行数据存储,所以先准备一个 Etcd 数据库,为了解决 Etcd 单点故障,应采用集群方式部署,这里使用 3 台组建集群,可容忍一台机器故障,当然也可以使用 5 台组件集群,可以容忍 2 台机器故障。
1、为 etcd 和 apiserver 自签证书【k8smaster1 节点操作】
创建工作目录:
mkdir -p TLS/{etcd,k8s}
cd TLS/etcd/
准备 cfssl 证书生成工具:
# 原地址【下载太慢】 建议迅雷下载
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
# 码云地址【个人上传】
wget https://gitee.com/bbigsun/kubernetes-study/raw/master/TLS/etcd/cfssl_linux-amd64
wget https://gitee.com/bbigsun/kubernetes-study/raw/master/TLS/etcd/cfssljson_linux-amd64
wget https://gitee.com/bbigsun/kubernetes-study/raw/master/TLS/etcd/cfssl-certinfo_linux-amd64
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64 cfssl-certinfo_linux-amd64
mv cfssl_linux-amd64 /usr/local/bin/cfssl
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
【使用自签 CA 生成 etcd 证书】
【① 自签 CA】:
cat > ca-config.json<<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"www": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat > ca-csr.json<<EOF
{
"CN": "etcd CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"BL": "Beijing"
}
]
}
EOF
【② 签发 etcd 证书】:
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
ls *pem
【使用自签 CA 签发 Etcd HTTPS 证书】:
【① 自签 CA】
创建证书申请文件:(文件 hosts 字段中 IP 为所有 etcd 节点的集群内部通信 IP,一个都不能少!为了 方便后期扩容可以多写几个预留的 IP)
cat > server-csr.json << EOF
{
"CN": "etcd",
"hosts": [
"192.168.60.151",
"192.168.60.152",
"192.168.60.153"
],
"key": {
"algo": "rsa",
"size": 2048
},
"name": [
{
"C": "CN",
"L": "Beijing",
"SL": "Beijing"
}
]
}
EOF
【② 签发 etcd https 证书】
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
ls server*pem
2、部署 etcd【k8smaster1 节点操作】
从 GitHub 下载二进制文件:
# 原地址【下载太慢】/ 建议迅雷下载
wget https://github.com/etcd-io/etcd/releases/download/v3.4.9/etcd-v3.4.9-linux-amd64.tar.gz
# 码云地址【个人上传】
wget https://gitee.com/bbigsun/kubernetes-study/raw/master/TLS/etcd/etcd-v3.4.9-linux-amd64.tar.gz
安装 etcd:
mkdir -p /opt/etcd/{bin,cfg,ssl}
tar -zxvf etcd-v3.4.9-linux-amd64.tar.gz
mv etcd-v3.4.9-linux-amd64/{etcd,etcdctl} /opt/etcd/bin/
cp ~/TLS/etcd/ca*pem ~/TLS/etcd/server*pem /opt/etcd/ssl/
创建配置文件:
cat > /opt/etcd/cfg/etcd.conf << EOF
#[Member]
ETCD_NAME="etcd-1"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.60.151:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.60.151:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.60.151:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.60.151:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.60.151:2380,etcd-2=https://192.168.60.152:2380,etcd-3=https://192.168.60.153:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
# 名词解释
# ETCD_NAME:节点名称,集群中唯一
# ETCD_DATA_DIR:数据目录
# ETCD_LISTEN_PEER_URLS:集群通信监听地址
# ETCD_LISTEN_CLIENT_URLS:客户端访问监听地址
# ETCD_INITIAL_ADVERTISE_PEER_URLS:集群通告地址
# ETCD_ADVERTISE_CLIENT_URLS:客户端通告地址
# ETCD_INITIAL_CLUSTER:集群节点地址
# ETCD_INITIAL_CLUSTER_TOKEN:集群 Token
# ETCD_INITIAL_CLUSTER_STATE:加入集群的当前状态,new 是新集群,existing 表示加入 已有集群
创建 etcd.service:
cat > /usr/lib/systemd/system/etcd.service << EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
EnvironmentFile=/opt/etcd/cfg/etcd.conf
ExecStart=/opt/etcd/bin/etcd \
--cert-file=/opt/etcd/ssl/server.pem \
--key-file=/opt/etcd/ssl/server-key.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem \
--peer-key-file=/opt/etcd/ssl/server-key.pem \
--trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/opt/etcd/ssl/ca.pem \
--logger=zap
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
【k8smaster1 配置完毕!】
3、转发 etcd 到 node 节点【k8smaster1 节点上操作】【需要输入密码,建议密码设置简单一点】
###### 转发到 k8snode1 ######
scp -r /opt/etcd/ root@192.168.60.152:/opt/
scp -r /usr/lib/systemd/system/etcd.service root@192.168.60.152:/usr/lib/systemd/system/
###### 转发到 k8snode2 ######
scp -r /opt/etcd/ root@192.168.60.153:/opt/
scp -r /usr/lib/systemd/system/etcd.service root@192.168.60.153:/usr/lib/systemd/system/
4、修改 node 节点上 etcd 的配置文件:IP 和名字【k8snode1 和 k8snode2 节点上操作】
##### k8sndoe1上操作 #####
cat > /opt/etcd/cfg/etcd.conf << EOF
#[Member]
ETCD_NAME="etcd-2"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.60.152:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.60.152:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.60.152:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.60.152:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.60.151:2380,etcd-2=https://192.168.60.152:2380,etcd-3=https://192.168.60.153:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
##### k8sndoe2上操作 #####
cat > /opt/etcd/cfg/etcd.conf << EOF
#[Member]
ETCD_NAME="etcd-3"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.60.153:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.60.153:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.60.153:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.60.153:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.60.151:2380,etcd-2=https://192.168.60.152:2380,etcd-3=https://192.168.60.153:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
启动并设置开机启动:【k8snode1 和 k8snode2 均需启动】
systemctl daemon-reload
systemctl start etcd
systemctl enable etcd
查看集群状态:
/opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.60.151:2379,https://192.168.60.152:2379,https://192.168.60.153:2379" endpoint status --write-out=table
# 2.2.6 安装 docker
在所有节点操作。这里采用二进制安装,用 yum 安装也一样 (多台节点安装可以采用键盘工具)
cd ~/TLS
wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.3.tgz
tar -zxvf docker-20.10.3.tgz
mv docker/ /usr/bin
systemd 管理 docker:
cat > /usr/lib/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
配置阿里云加速:
mkdir /etc/docker
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
启动并设置开机启动:
systemctl daemon-reload
systemctl start docker
systemctl enable docker
systemctl status docker
【k8smaster1 节点安装 docker 完毕!转发到 k8snode1 和 k8snode2 节点】【k8smaster1 节点上操作】
##### 转发到 k8snode1 #####
scp -r /usr/bin/docker/ root@192.168.60.152:/usr/bin/
scp -r /usr/lib/systemd/system/docker.service root@192.168.60.152:/usr/lib/systemd/system/
scp -r /etc/docker/ root@192.168.60.152:/etc/
##### 转发到 k8snode2 #####
scp -r /usr/bin/docker/ root@192.168.60.153:/usr/bin/
scp -r /usr/lib/systemd/system/docker.service root@192.168.60.153:/usr/lib/systemd/system/
scp -r /etc/docker/ root@192.168.60.153:/etc/
# 2.2.7 部署 master 组件
- kube-apiserver
- kuber-controller-manager
- kube-scheduler
1、安装 kube-apiserver
【生成 kube-apiserver 证书】
【① 自签证书颁发机构 CA】:
cd ~/TLS/k8s
cat > ca-config.json << EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat > ca-csr.json << EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
【② 生成 kube-apiserver 证书】:
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
ls *pem
【使用自签 CA 签发 kube-apiserver HTTPS 证书】
【① 创建证书申请文件】:
cat > server-csr.json << EOF
{
"CN": "kubernetes",
"hosts": [
"10.0.0.1",
"127.0.0.1",
"192.168.60.151",
"192.168.60.152",
"192.168.60.153",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
【② 生成 kube-apiserver https 证书】:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server
ls server*pem
【安装 kube-apiserver】
下载二进制包:
# 下载地址:https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.20.md
# kubernetes-server-linux-amd64.tar.gz 包含了master和node的所有组件
# 这里提供几个下载地址
wget https://storage.googleapis.com/kubernetes-release/release/v1.20.1/kubernetes-server-linux-amd64.tar.gz
wget https://dl.k8s.io/v1.19.0/kubernetes-server-linux-amd64.tar.gz
# 码云地址【个人上传】【推荐】
wget https://gitee.com/bbigsun/kubernetes-study/raw/master/TLS/k8s/kubernetes-server-linux-amd64.tar.gz
解压二进制包:
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
tar -zxvf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin
cp kube-apiserver kube-scheduler kube-controller-manager /opt/kubernetes/bin
cp kubectl /usr/bin/
生成 kube-apiserver 配置文件:
cat > /opt/kubernetes/cfg/kube-apiserver.conf << EOF
KUBE_APISERVER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--etcd-servers=https://192.168.60.151:2379,https://192.168.60.152:2379,https://192.168.60.153:2379 \\
--bind-address=192.168.60.151 \\
--secure-port=6443 \\
--advertise-address=192.168.60.151 \\
--allow-privileged=true \\
--service-cluster-ip-range=10.0.0.0/24 \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \\
--authorization-mode=RBAC,Node \\
--enable-bootstrap-token-auth=true \\
--token-auth-file=/opt/kubernetes/cfg/token.csv \\
--service-node-port-range=30000-32767 \\
--kubelet-client-certificate=/opt/kubernetes/ssl/server.pem \\
--kubelet-client-key=/opt/kubernetes/ssl/server-key.pem \\
--tls-cert-file=/opt/kubernetes/ssl/server.pem \\
--tls-private-key-file=/opt/kubernetes/ssl/server-key.pem \\
--client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--etcd-cafile=/opt/etcd/ssl/ca.pem \\
--etcd-certfile=/opt/etcd/ssl/server.pem \\
--etcd-keyfile=/opt/etcd/ssl/server-key.pem \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/opt/kubernetes/logs/k8s-audit.log"
EOF
# 注:上面两个\ \ 第一个是转义符,第二个是换行符,使用转义符是为了使用 EOF 保留换 行符。
# –logtostderr:启用日志
# —v:日志等级
# –log-dir:日志目录
# –etcd-servers:etcd 集群地址
# –bind-address:监听地址
# –secure-port:https 安全端口
# –advertise-address:集群通告地址
# –allow-privileged:启用授权
# –service-cluster-ip-range:Service 虚拟 IP 地址段
# –enable-admission-plugins:准入控制模块
# –authorization-mode:认证授权,启用 RBAC 授权和节点自管理
# –enable-bootstrap-token-auth:启用 TLS bootstrap 机制
# –token-auth-file:bootstrap token 文件
# –service-node-port-range:Service nodeport 类型默认分配端口范围
# –kubelet-client-xxx:apiserver 访问 kubelet 客户端证书
# –tls-xxx-file:apiserver https 证书
# –etcd-xxxfile:连接 Etcd 集群证书
# –audit-log-xxx:审计日志
把刚生成的证书拷贝到配置文件中的路径:
cp ~/TLS/k8s/ca*pem ~/TLS/k8s/server*pem /opt/kubernetes/ssl/
创建上述文件配置文件中的 token 文件:
cat > /opt/kubernetes/cfg/token.csv << EOF
c47ffb939f5ca36231d9e3121a252940,kubelet-bootstrap,10001,"system:node-bootstrapper"
EOF
格式:token,用户名,UID,用户组 token 也可自行生成替换【建议暂时不要替换,直接 copy 代码就完事了】:
head -c 16 /dev/urandom | od -An -t x | tr -d ' '
systemd 管理 apiserver:
cat > /usr/lib/systemd/system/kube-apiserver.service << EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-apiserver.conf
ExecStart=/opt/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
启动并设置开机启动:
systemctl daemon-reload
systemctl start kube-apiserver
systemctl enable kube-apiserver
systemctl status kube-apiserver
授权 kubelet-bootstrap 用户允许请求证书:
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap
2、部署 kube-controller-manager
cat > /opt/kubernetes/cfg/kube-controller-manager.conf << EOF
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--master=127.0.0.1:8080 \\
--bind-address=127.0.0.1 \\
--allocate-node-cidrs=true \\
--cluster-cidr=10.244.0.0/16 \\
--service-cluster-ip-range=10.0.0.0/24 \\
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--root-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--experimental-cluster-signing-duration=87600h0m0s"
EOF
# –master:通过本地非安全本地端口 8080 连接 apiserver。
# –leader-elect:当该组件启动多个时,自动选举(HA)
# –cluster-signing-cert-file/–cluster-signing-key-file:自动为 kubelet 颁发证书的 CA,与 apiserver 保持一致
systemd 管理 controller-manager:
cat > /usr/lib/systemd/system/kube-controller-manager.service << EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-controller-manager.conf
ExecStart=/opt/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
启动并设置开机启动:
systemctl daemon-reload
systemctl start kube-controller-manager
systemctl enable kube-controller-manager
systemctl status kube-controller-manager
3、部署 kube-scheduler
cat > /opt/kubernetes/cfg/kube-scheduler.conf << EOF
KUBE_SCHEDULER_OPTS="--logtostderr=false \
--v=2 \
--log-dir=/opt/kubernetes/logs \
--leader-elect \
--master=127.0.0.1:8080 \
--bind-address=127.0.0.1"
EOF
# 参数说明
# –master:通过本地非安全本地端口 8080 连接 apiserver。
# –leader-elect:当该组件启动多个时,自动选举(HA)
cat > /usr/lib/systemd/system/kube-scheduler.service << EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-scheduler.conf
ExecStart=/opt/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
启动并设置开机启动:
systemctl daemon-reload
systemctl start kube-scheduler
systemctl enable kube-scheduler
systemctl status kube-scheduler
4、查看集群状态
所有组件都已经启动成功,通过 kubectl 工具查看当前集群组件状态:
kubectl get cs
# 2.2.8 部署 node 组件
- kubelet
- kube-proxy
1、安装 kubelet
##### k8snode1节点上操作 #####
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
cat > /opt/kubernetes/cfg/kubelet.conf << EOF
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--hostname-override=m1 \\
--network-plugin=cni \\
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \\
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \\
--config=/opt/kubernetes/cfg/kubelet-config.yml \\
--cert-dir=/opt/kubernetes/ssl \\
--pod-infra-container-image=lizhenliang/pause-amd64:3.0"
EOF
# –hostname-override:显示名称,集群中唯一
# –network-plugin:启用CNI
# –kubeconfig:空路径,会自动生成,后面用于连接apiserver
# –bootstrap-kubeconfig:首次启动向apiserver申请证书
# –config:配置参数文件
# –cert-dir:kubelet证书生成目录
# –pod-infra-container-image:管理Pod网络容器的镜像
cat > /opt/kubernetes/cfg/kubelet-config.yml << EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: 0.0.0.0
port: 10250
readOnlyPort: 10255
cgroupDriver: cgroupfs
clusterDNS:
- 10.0.0.2
clusterDomain: cluster.local
failSwapOn: false
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /opt/kubernetes/ssl/ca.pem
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
evictionHard:
imagefs.available: 15%
memory.available: 100Mi
nodefs.available: 10%
nodefs.inodesFree: 5%
maxOpenFiles: 1000000
maxPods: 110
EOF
将 k8smaster1 节点的 bin 文件和证书拷贝到 k8snode1 和 k8snode2 节点上【k8smaster1 节点操作】:
cd ~/TLS/k8s/kubernetes/server/bin
##### 转发到 k8snode1 #####
scp -r {kubelet,kube-proxy} root@192.168.60.152:/opt/kubernetes/bin/
scp -r /usr/bin/kubectl root@192.168.60.152:/usr/bin/
scp -r /opt/kubernetes/ssl root@192.168.60.152:/opt/kubernetes
##### 转发到 k8snode2 #####
scp -r /opt/kubernetes/ssl root@192.168.60.153:/opt/kubernetes
生成 bootstrap.kubeconfig 文件:
# apiserver IP:PORT
KUBE_APISERVER="https://192.168.60.151:6443"
# 与token.csv里保持一致
TOKEN="c47ffb939f5ca36231d9e3121a252940"
生成 kubelet bootstrap kubeconfig 配置文件:
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=bootstrap.kubeconfig
kubectl config set-credentials "kubelet-bootstrap" \
--token=${TOKEN} \
--kubeconfig=bootstrap.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user="kubelet-bootstrap" \
--kubeconfig=bootstrap.kubeconfig
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
mv bootstrap.kubeconfig /opt/kubernetes/cfg
systemd 管理 kubelet:
cat > /usr/lib/systemd/system/kubelet.service << EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kubelet.conf
ExecStart=/opt/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
启动并设置开机启动:
systemctl daemon-reload
systemctl start kubelet
systemctl enable kubelet
systemctl status kubelet
批准 kubelet 证书申请并加入集群【k8smaster1 节点操作】:
# 查看kubelet证书请求
kubectl get csr
### 输出结果
### NAME AGE SIGNERNAME REQUESTOR CONDITION
### node-csr-uCEGPOIiDdlLODKts8J658HrFq9CZ--K6M4G7bjhk8A 6m3s kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Pending
# 批准申请
kubectl certificate approve node-csr-uCEGPOIiDdlLODKts8J658HrFq9CZ--K6M4G7bjhk8A
# 查看节点
kubectl get node
注:由于网络插件还没有部署,节点会没有准备就绪 NotReady
2、部署 kube-proxy
cat > /opt/kubernetes/cfg/kube-proxy.conf << EOF
KUBE_PROXY_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--config=/opt/kubernetes/cfg/kube-proxy-config.yml"
EOF
cat > /opt/kubernetes/cfg/kube-proxy-config.yml << EOF
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
metricsBindAddress: 0.0.0.0:10249
clientConnection:
kubeconfig: /opt/kubernetes/cfg/kube-proxy.kubeconfig
hostnameOverride: m1
clusterCIDR: 10.0.0.0/24
EOF
生成 kube-proxy.kubeconfig 文件【k8smaster1 生成再传到 k8snode1 和 k8snode2】:
# 切换工作目录
cd ~/TLS/k8s
# 创建证书请求文件
cat > kube-proxy-csr.json << EOF
{
"CN": "system:kube-proxy",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
# 生成证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
# 生成kubeconfig文件
KUBE_APISERVER="https://192.168.60.151:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/opt/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kube-proxy.kubeconfig
kubectl config set-credentials kube-proxy \
--client-certificate=./kube-proxy.pem \
--client-key=./kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=kube-proxy.kubeconfig
kubectl config set-context default \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
##### 转发到 k8snode1 #####
scp -r kube-proxy.kubeconfig root@192.168.60.152:/opt/kubernetes/cfg/
##### 转发到 k8snode2 #####
scp -r kube-proxy.kubeconfig root@192.168.60.153:/opt/kubernetes/cfg/
systemd 管理 kube-proxy:
cat > /usr/lib/systemd/system/kube-proxy.service << EOF
[Unit]
Description=Kubernetes Proxy
After=network.target
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kube-proxy.conf
ExecStart=/opt/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
启动并设置开机启动:
systemctl daemon-reload
systemctl start kube-proxy
systemctl enable kube-proxy
systemctl status kube-proxy
# 2.2.9 部署 CNI 网络插件
下载 CNI 网络插件:
# 原地址
wget https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-amd64-v0.8.6.tgz
# 码云地址【个人上传】【推荐】【速度较快】
wget https://gitee.com/bbigsun/kubernetes-study/raw/master/TLS/k8s/cni-plugins-linux-amd64-v0.8.6.tgz
安装插件:
mkdir -p /opt/cni/bin
tar -zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin
【k8smaster1 节点操作】:
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f kube-flannel.yml
# 2.2.10 测试 kubernetes 集群
在 Kubernetes 集群中创建一个 pod,验证是否正常运行【master 节点操作】:
# 下载nginx 【会联网拉取nginx镜像】
kubectl create deployment nginx --image=nginx
# 查看状态
kubectl get pod
如果我们出现 Running 状态的时候,表示已经成功运行了
下面我们就需要将端口暴露出去,让其它外界能够访问
# 暴露端口
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看一下对外的端口
kubectl get pod,svc
能够看到,我们已经成功暴露了 80 端口 到 30529 上
我们到我们的宿主机浏览器上,访问如下地址
http://192.168.177.130:30529/
发现我们的 nginx 已经成功启动了
# 2.3 两种方式搭建集群的对比
# 2.3.1 Kubeadm 方式搭建 K8S 集群
- 安装虚拟机,在虚拟机安装 Linux 操作系统【3 台虚拟机】
- 对操作系统初始化操作
- 所有节点安装 Docker、kubeadm、kubelet、kubectl【包含 master 和 node 节点】
- 安装 Docker、使用 yum,不指定版本默认安装最新的 Docker 版本
- 修改 Docker 仓库地址,yum 源地址,改为阿里云地址
- 安装 kubeadm,kubelet 和 kubectl
- k8s 已经发布最新的 1.19 版本,可以指定版本安装,不指定安装最新版本
yum install -y kubelet kubeadm kubectl
- 在 master 节点执行初始化命令操作
kubeadm init
- 默认拉取镜像地址 K8s.gcr.io 国内地址,需要使用国内地址
- 安装网络插件 (CNI)
kubectl apply -f kube-flannel.yml
- 在所有的 node 节点上,使用 join 命令,把 node 添加到 master 节点上
- 测试 kubernetes 集群
# 2.3.2 二进制方式搭建 K8S 集群
- 安装虚拟机和操作系统,对操作系统进行初始化操作
- 生成 cfssl 自签证书
ca-key.pem
、ca.pem
server-key.pem
、server.pem
- 部署 Etcd 集群
- 部署的本质,就是把 etcd 集群交给 systemd 管理
- 把生成的证书复制过来,启动,设置开机启动
- 安装 Docker
- 部署 master 组件,主要包含以下组件
- apiserver
- controller-manager
- scheduler
- 交给 systemd 管理,并设置开机启动
- 如果要安装最新的 1.19 版本,下载二进制文件进行安装
- 部署 node 组件
- kubelet
- kube-proxy【需要批准 kubelet 证书申请加入集群】
- 交给 systemd 管理组件 - 组件启动,设置开机启动
- 批准 kubelet 证书申请 并加入集群
- 部署 CNI 网络插件
- 测试 Kubernets 集群【安装 nginx 测试】
# 3 Kubernetes 核心概念
# 3.1 kubernetes 集群命令行工具 kubectl
# 3.1.1 kubectl 概述
kubectl 是 Kubernetes 集群的命令行工具,通过 kubectl 能够对集群本身进行管理,并能够在集群上进行容器化应用的安装和部署。
# 3.1.2 kubectl 命令格式
kubectl [command] [type] [name] [flags]
参数:
-
command:指定要对资源执行的操作,例如 create、get、describe、delete
-
type:指定资源类型,资源类型是大小写敏感的,开发者能够以单数 、复数 和 缩略的形式
kubectl get pod pod1 kubectl get pods pod1 kubectl get po pod1
-
name:指定资源的名称,名称也是大小写敏感的,如果省略名称,则会显示所有的资源,例如
kubectl get pods
-
flags:指定可选的参数,例如,可用 -s 或者 -server 参数指定 Kubernetes API server 的地址和端口
# 3.1.3 kubectl 帮助命令
# 获取kubectl的命令
kubectl --help
# 获取某个命令的介绍和使用
kubectl get --help
kubectl create --help
# 3.1.4 kubectl 基础命令
命令 | 介绍 |
---|---|
create | 通过文件名或标准输入创建资源 |
expose | 将一个资源公开为一个新的 Service |
run | 在集群中运行一个特定的镜像 |
set | 在对象上设置特定的功能 |
get | 显示一个或多个资源 |
explain | 文档参考资料 |
edit | 使用默认的编辑器编辑一个资源 |
delete | 通过文件名,标准输入,资源名称或标签来删除资源 |
# 3.1.5 kubectl 部署命令
命令 | 介绍 |
---|---|
rollout | 管理资源的发布 |
rolling-update | 对给定的复制控制器滚动更新 |
scale | 扩容或缩容 Pod 数量,Deployment、ReplicaSet、RC 或 Job |
autoscale | 创建一个自动选择扩容或缩容并设置 Pod 数量 |
# 3.1.6 kubectl 集群管理命令
命令 | 介绍 |
---|---|
certificate | 修改证书资源 |
cluster-info | 显示集群信息 |
top | 显示资源 (CPU/M) |
cordon | 标记节点不可调度 |
uncordon | 标记节点可被调度 |
drain | 驱逐节点上的应用,准备下线维护 |
taint | 修改节点 taint 标记 |
# 3.1.7 kubectl 故障和调试命令
命令 | 介绍 |
---|---|
describe | 显示特定资源或资源组的详细信息 |
logs | 在一个 Pod 中打印一个容器日志,如果 Pod 只有一个容器,容器名称是可选的 |
attach | 附加到一个运行的容器 |
exec | 执行命令到容器 |
port-forward | 转发一个或多个 |
proxy | 运行一个 proxy 到 Kubernetes API Server |
cp | 拷贝文件或目录到容器中 |
auth | 检查授权 |
# 3.1.8 kubectl 其它命令
命令 | 介绍 |
---|---|
apply | 通过文件名或标准输入对资源应用配置 |
patch | 使用补丁修改、更新资源的字段 |
replace | 通过文件名或标准输入替换一个资源 |
convert | 不同的 API 版本之间转换配置文件 |
label | 更新资源上的标签 |
annotate | 更新资源上的注释 |
completion | 用于实现 kubectl 工具自动补全 |
api-versions | 打印受支持的 API 版本 |
config | 修改 kubeconfig 文件(用于访问 API,比如配置认证信息) |
help | 所有命令帮助 |
plugin | 运行一个命令行插件 |
version | 打印客户端和服务版本信息 |
# 3.2 Kubernetes 集群 YAML 文件详解
参考资料:YAML 入门教程 | 菜鸟教程
# 3.2.1 YAML 概述
- YAML 文件:就是资源清单文件,用于资源编排。
- YAML : 仍是一种标记语言。为了强调这种语言以数据做为中心,而不是以标记语言为重点。
- YAML : 是一个可读性高,用来表达数据序列的格式。
# 3.2.2 YAML 基本语法
- 使用空格做为缩进
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
- 低版本缩进时不允许使用 Tab 键,只允许使用空格
- 使用 #标识注释,从这个字符一直到行尾,都会被解释器忽略
- 使用 — 表示新的 yaml 文件开始
# 3.2.3 YAML 数据结构
对象:键值对的集合,又称为映射 (mapping) / 哈希(hashes) / 字典(dictionary)
# 对象类型:对象的一组键值对,使用冒号结构表示
name: Tom
age: 18
# yaml 也允许另一种写法,将所有键值对写成一个行内对象
hash: {name: Tom, age: 18}
数组:
# 数组类型:一组连词线开头的行,构成一个数组
People
- Tom
- Jack
# 数组也可以采用行内表示法
People: [Tom, Jack]
# 3.2.4 YAML 组成部分
主要分为了两部分,一个是控制器的定义 和 被控制的对象。
在一个 YAML 文件的控制器定义中,有很多属性名称
属性名称 | 介绍 |
---|---|
apiVersion | API 版本 |
kind | 资源类型 |
metadata | 资源元数据 |
spec | 资源规格 |
replicas | 副本数量 |
selector | 标签选择器 |
template | Pod 模板 |
metadata | Pod 元数据 |
spec | Pod 规格 |
containers | 容器配置 |
# 3.2.5 YAML 快速编写
一般来说,我们很少自己手写 YAML 文件,因为这里面涉及到了很多内容,我们一般都会借助工具来创建
1、使用 kubectl create 命令
这种方式一般用于资源没有部署的时候,我们可以直接创建一个 YAML 配置文件
# 尝试运行,并不会真正的创建镜像
kubectl create deployment web --image=nginx -o yaml --dry-run
或者我们可以输出到一个文件中
kubectl create deployment web --image=nginx -o yaml --dry-run > hello.yaml
然后我们就在文件中直接修改即可
2、使用 kubectl get 命令导出 yaml 文件
可以首先查看一个目前已经部署的镜像
kubectl get deploy
然后我们导出 nginx 的配置
kubectl get deploy nginx -o=yaml --export > nginx.yaml
然后会生成一个 nginx.yaml
的配置文件
# 3.3 Pod
# 3.3.1 Pod 概述
1、Pod 基本概念
- 最小部署的单元
- Pod 里面是由一个或多个容器组成【一组容器的集合】
- 一个 pod 中的容器是共享网络命名空间
- Pod 是短暂的
- 每个 Pod 包含一个或多个紧密相关的用户业务容器
2、Pod 存在的意义
- 创建容器使用 docker,一个 docker 对应一个容器,一个容器运行一个应用进程
- Pod 是多进程设计,运用多个应用程序,也就是一个 Pod 里面有多个容器,而一个容器里面运行一个应用程序
- Pod 的存在是为了亲密性应用
- 两个应用之间进行交互
- 网络之间的调用【通过 127.0.0.1 或 socket】
- 两个应用之间需要频繁调用
3、k8s 业务类型
Pod 是 K8S 集群中所有业务类型的基础,可以把 Pod 看作运行在 K8S 集群上的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前 K8S 的业务主要可以分为以下几种
- 长期伺服型:long-running
- 批处理型:batch
- 节点后台支撑型:node-daemon
- 有状态应用型:stateful application
上述的几种类型,分别对应的小机器人控制器为:Deployment、Job、DaemonSet 和 StatefulSet (后面将介绍控制器)
# 3.3.2 Pod 实现机制
Pod 主要有以下两大机制:共享网络 和 共享存储。
1、共享网络【容器通过 namespace 和 group 进行隔离】
Pod 中容器通信 过程:
- 同一个 namespace 下
- 在 Pod 中创建一个根容器:
pause容器
- 在 Pod 中创建业务容器 【nginx,redis 等】【创建时会添加到
info容器
中】 - 在
info容器
中会独立出 ip 地址,mac 地址,port 等信息,然后实现网络的共享
2、共享存储【Pod 持久化数据,专门存储到某个地方中,使用 Volumn 数据卷进行共享存储】
# 3.3.3 Pod 镜像拉取策略
我们以具体实例来说,拉取策略就是
imagePullPolicy
拉取策略主要分为了以下几种:
IfNotPresent
:默认值,镜像在宿主机上不存在才拉取Always
:每次创建 Pod 都会重新拉取一次镜像Never
:Pod 永远不会主动拉取这个镜像
# 3.3.4 Pod 资源限制
也就是我们 Pod 在进行调度的时候,可以对调度的资源进行限制,例如我们限制 Pod 调度是使用的资源是 2C4G,那么在调度对应的 node 节点时,只会占用对应的资源,对于不满足资源的节点,将不会进行调度。
这里分了两个部分:
request
:表示调度所需的资源limits
:表示最大所占用的资源
# 3.3.5 Pod 重启机制
因为 Pod 中包含了很多个容器,假设某个容器出现问题了,那么就会触发 Pod 重启机制
重启策略主要分为以下三种:
Always
:当容器终止退出后,总是重启容器,默认策略 【nginx 等,需要不断提供服务】OnFailure
:当容器异常退出(退出状态码非 0)时,才重启容器。Never
:当容器终止退出,从不重启容器 【批量任务】
# 3.3.6 Pod 健康检查
1、通过容器检查
kubectl get pod
2、通过应用检查
但是有的时候,程序可能出现了 Java 堆内存溢出,程序还在运行,但是不能对外提供服务了,这个时候就不能通过容器检查来判断服务是否可用了。需要通过应用检查。
# 存活检查,如果检查失败,将杀死容器,根据Pod的restartPolicy【重启策略】来操作
livenessProbe
# 就绪检查,如果检查失败,Kubernetes会把Pod从Service endpoints中剔除
readinessProbe
Probe 支持以下三种检查方式
http Get
:发送 HTTP 请求,返回 200 - 400 范围状态码为成功exec
:执行 Shell 命令返回状态码是 0 为成功tcpSocket
:发起 TCP Socket 建立成功
# 3.3.7 Pod 调度策略
创建 Pod 流程:
- 首先创建一个 pod,然后创建一个 API Server 和 Etcd【把创建出来的信息存储在 etcd 中】
- 然后创建 Scheduler,监控 API Server 是否有新的 Pod,如果有的话,会通过调度算法,把 pod 调度某个 node 上
- 在 node 节点,会通过
kubelet -- apiserver
读取 etcd 拿到分配在当前 node 节点上的 pod,然后通过 docker 创建容器
# 3.2 Controller
# 3.2.1 Controller 内容简介
- 什么是 Controler
- Pod 和 Controller 的关系
- Deployment 控制器应用场景
- yaml 文件字段说明
- Deployment 控制器部署应用
- 升级回滚
- 弹性收缩
# 3.2.2 Controller 概述
Controller 是集群上管理和运行容器的对象
- Controller 是实际存在的
- Pod 是虚拟机的
# 3.2.3 Pod 和 Controller 的关系
Pod 是通过 Controller 实现应用的运维,比如弹性收缩,滚动升级。
Pod 和 Controller 之间是通过 label 标签建立关系,同时 Controller 又被称为控制器工作负载。
- Controller【控制器】【工作负载】
selector: app:nginx
- Pod【容器】
labels: app:nginx
# 3.2.4 Deployment 控制器应用
Deployment 表示用户对 K8S 集群的一次更新操作。
- Deployment 控制器可以部署无状态应用
- 管理 Pod 和 ReplicaSet
- 部署,滚动升级等功能
- 应用场景:web 服务,微服务
# 3.2.5 Deployment 部署应用
之前,使用 Deploment 部署应用,代码如下:【缺点:代码不好复用】
kubectrl create deployment web --image=nginx
现在,使用 YAML 文件进行配置:【快速编写 YAML 文件】
kubectl create deployment web --image=nginx -o yaml --dry-run > nginx.yaml
nginx.yaml
文件内容如下:【 selector
和 label
就是我们 Pod 和 Controller 之间建立关系的桥梁】
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
# Pod
labels:
app: web
name: web
spec:
replicas: 1
# Controller
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}
现在,使用 nginx.yaml
文件创建镜像:
kubectl apply -f nginx.yaml
然后,对外暴露端口:
kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web1
# 参数说明
# --port:就是我们内部的端口号
# --target-port:就是暴露外面访问的端口号
# --name:名称
# --type:类型
同理,导出配置文件:
kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web1 -o yaml > web1.yaml
查看端口:
kubectl get pods,svc
# 输出结果
NAME READY STATUS RESTARTS AGE
pod/web-5dcb957ccc-d89v9 1/1 Running 0 8m35s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d5h
service/web1 NodePort 10.111.61.143 <none> 80:30344/TCP 6s
然后我们访问对应的 url,即可看到 nginx 了 http://192.168.60.151:30344/
# 3.2.6 升级回滚和弹性收缩
- 升级: 假设从版本为 1.14 升级到 1.15 ,这就叫应用的升级【升级可以保证服务不中断】
- 回滚:从版本 1.15 变成 1.14,这就叫应用的回滚
- 弹性伸缩:我们根据不同的业务场景,来改变 Pod 的数量对外提供服务,这就是弹性伸缩
1、创建一个 1.14 版本的 pod
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
# 修改nginx版本 1.14
- image: nginx:1.14
name: nginx
resources: {}
status: {}
kubectl apply -f nginx.yaml
2、应用升级
kubectl set image deployment web nginx=nginx:1.15
升级过程:
[root@k8smaster ~]# kubectl set image deployment web nginx=nginx:1.15
deployment.apps/web image updated
# 首先是开始的nginx 1.14版本的Pod在运行,然后 1.15版本的在创建
[root@k8smaster ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-66bf4959f5-qhzsd 1/1 Running 0 52s
web-bbcf684cb-bbmqv 0/1 ContainerCreating 0 3s
# 然后在1.15版本创建完成后,就会暂停1.14版本
[root@k8smaster ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-66bf4959f5-qhzsd 1/1 Terminating 0 67s
web-bbcf684cb-bbmqv 1/1 Running 0 18s
# 最后把1.14版本的Pod移除,完成我们的升级
[root@k8smaster ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-bbcf684cb-bbmqv 1/1 Running 0 33s
我们在下载 1.15 版本,容器就处于 ContainerCreating 状态,然后下载完成后,就用 1.15 版本去替换 1.14 版本了,这么做的好处就是:升级可以保证服务不中断
3、查看升级状态
kubectl rollout status deployment web
4、查看历史版本
kubectl rollout history deployment web
5、应用回滚
# 回滚到上一版本
kubectl rollout undo deployment web
# 回滚到指定版本
kubectl rollout undo deployment web --to-revision=2
6、弹性伸缩
# 通过命令创建多个副本
kubectl scale deployment web --replicas=10
# 输出结果,等一会就会全部Running
[root@k8smaster ~]# kubectl scale deployment web --replicas=10
deployment.apps/web scaled
[root@k8smaster ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-bbcf684cb-2f2zl 0/1 ContainerCreating 0 4s
web-bbcf684cb-72pzr 0/1 ContainerCreating 0 4s
web-bbcf684cb-bbmqv 1/1 Running 0 3m9s
web-bbcf684cb-fgpgh 0/1 ContainerCreating 0 4s
web-bbcf684cb-fpk8d 0/1 ContainerCreating 0 4s
web-bbcf684cb-hqp4z 0/1 ContainerCreating 0 4s
web-bbcf684cb-htq2d 0/1 ContainerCreating 0 4s
web-bbcf684cb-lnkwx 0/1 ContainerCreating 0 4s
web-bbcf684cb-vmwb9 0/1 ContainerCreating 0 4s
web-bbcf684cb-vnk5w 0/1 ContainerCreating 0 4s
# 3.3 Kubernetes 配置管理
# 3.3.1 Secret
Secret 的主要作用就是加密数据
1、Secret 应用场景
对 用户名 和 密码 进行加密
2、Secret 三种类型
Opaque
:使用 base64 编码存储信息,可以通过 base64 --decode 解码获得原始数据,因此安全性弱。kubernetes.io/dockerconfigjson
:用于存储 docker registry 的认证信息。kubernetes.io/service-account-token
:用于被 serviceaccount 引用。serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。
3、Secret 创建
(1)命令行方式创建 Secret
echo -n "admin" > ./username.txt
echo -n "1f1f1f1f1f" > ./password.txt
# 使用 kubectl create secret 命令创建 secret
kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
# secret/db-user-pass created
# 查看secret
kubectl get secrets
# NAME TYPE DATA AGE
# db-user-pass Opaque 2 59s
(2)yaml 文件方式创建 Secret
echo -n 'admin' | base64
# YWRtaW4=
echo -n '1f1f1f1f1f' | base64
# MWYxZjFmMWYxZg==
# 创建secret:创建yaml文件
cat > secret.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYxZjFmMWYxZg==
EOF
# 创建secret:使用yaml文件创建secret
kubectl create -f secret.yaml
# secret/mysecret created
# 查看secret
kubectl get secrets | grep mysecret
# mysecret Opaque 2 32s
# 查看secret详细信息
kubectl describe secrets mysecret
# 查看secret yaml文件
kubectl get secrets mysecret -o yaml
4、Secret 使用【两种方式】
- 以 Volume 形式
- 以环境变量形式
(1)将 Secret 挂载到 Volume 中
cat > mypod1.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: mypod1
spec:
containers:
- name: mypod1
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
EOF
kubectl create -f mypod1.yaml
# pod/mypod1 created
kubectl get pods | grep mypod
# mypod1 1/1 Running 0 48s
kubectl exec -it mypod1 /bin/bash
## 查看密码和用户名
root@mypod1:/data# cd /etc/foo/
root@mypod1:/etc/foo# ls
password username
root@mypod1:/etc/foo# cat password
1f1f1f1f1f
root@mypod1:/etc/foo# cat username
admin
root@mypod1:/etc/foo#
(2)将 Secret 设置为环境变量
cat > mypod2.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: mypod2
spec:
containers:
- name: mypod2
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
restartPolicy: Never
EOF
kubectl create -f mypod2.yaml
# pod/mypod2 created
kubectl get pods | grep mypod
# mypod1 1/1 Running 0 4m39s
# mypod2 0/1 ContainerCreating 0 6s
# 等 mypod2 running 之后在进入容器
kubectl exec -it mypod2 /bin/bash
## 查看环境变量
root@mypod2:/data# env | grep -E "USERNAME|PASSWORD"
SECRET_USERNAME=admin
SECRET_PASSWORD=1f1f1f1f1f
# 3.3.2 ConfigMap
ConfigMap 作用是存储不加密的数据到 etcd 中
1、应用场景
配置文件
2、创建
(1)yaml 文件方式创建
cat > configmap-test01.yaml << EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-test01
data:
appconf01: value01
appconf02: value02
EOF
kubectl create -f configmap-test01.yaml
(2)命令行方式创建
读取文件方式(也可以是目录)通过
--from-file
参数从文件中读取。可以指定 key 的名称,若不指定,则默认使用文件名为 key。
cat > test.properties << EOF
key01:value01
key02:value02
conf01: value03
EOF
kubectl create cm cm-test-file --from-file=test.properties
3、查询
# 查看configmap列表
kubectl get configmap
# 查看configmap详情
kubectl describe configmap cm-test01
kubectl describe configmap cm-test-file
kubectl describe cm cm-test-literal
# 查看yaml输出
kubectl get cm cm-test01 -o yaml
kubectl get configmap cm-test-file -o yaml
kubectl get cm cm-test-literal -o yaml
4、更新
# 方式一:edit
kubectl edit cm cm-test01
# 查看更新是否生效
kubectl describe cm cm-test01
# 方式二:apply
kubectl apply -f configmap-test01.yaml
5、删除
# 方式一:通过yaml文件删除
kubectl delete -f configmap-test01.yaml
# 方式二:直接删除资源
kubectl delete cm cm-test-file
6、使用 【yaml 文件有误,以下四种方式无误】
容器应用对 ConfigMap 的使用主要是两种:
- 通过环境变量获取 ConfigMap 的内容:
spec.env
和spec.envFrom
- 通过卷 volume 挂载的方式将 ConfigMap 的内容挂载到容器内部的文件或目录:
spec.volumes
(1) spec.env
【环境变量】
vim pod-test01.yaml
apiVersion: v1
kind: Pod
metadata:
name: cm-pod-test001
spec:
containers:
- name: cm-test
image: tomcat:8
command: [ "/bin/sh", "-c", "env | grep APP"]
env:
- name: APPCONF01 # 定义环境变量的名称
valueFrom: # key “appconf01”的值获取
configMapKeyRef:
name: cm-test01 # 环境变量的值来自于configmap cm-test01
key: appconf01 # configmap中的配置key为appconf01
- name: APPCONF02 # 定义环境变量的名称
valueFrom: # key “appconf02”的值获取
configMapKeyRef:
name: cm-test01 # 环境变量的值来自于configmap cm-test01
key: appconf02 # configmap中的配置key为appconf02
restartPolicy: Never # 重启策略:从不。
kubectl create -f pod-test01.yaml
kubectl get pods | grep cm
kubectl logs cm-pod-test001
(2) spec.envFrom
【环境变量】
vim pod-test02.yaml
apiVersion: v1
kind: Pod
metadata:
name: cm-pod-test002
spec:
containers:
- name: cm-test2
image: tomcat:8
command: [ "/bin/sh", "-c", "env"]
envFrom:
- configMapRef:
name: cm-test01 # 根据ConfigMap cm-test01资源自动生成环境变量
restartPolicy: Never
kubectl create -f pod-test02.yaml
kubectl get po
(3)指定 items【卷挂载方式】
vim pod-test03.yaml
apiVersion: v1
kind: Pod
metadata:
name: cm-pod-test003
spec:
containers:
- name: cm-test3
image: tomcat:8
volumeMounts:
- name: vm-01-1
mountPath: /conf
volumes:
- name: vm-01-1
configMap:
name: cm-test-file
items:
- key: key-testproperties
path: test.properties
restartPolicy: Never
kubectl create -f pod-test03.yaml
kubectl get po
(4)不指定 items【卷挂载方式】
vim pod-test04.yaml
apiVersion: v1
kind: Pod
metadata:
name: cm-pod-test004
spec:
containers:
- name: cm-test4
image: tomcat:8
volumeMounts:
- name: vm-02-2
mountPath: /conf
volumes:
- name: vm-02-2
configMap:
name: cm-test-file
restartPolicy: Never
kubectl create -f pod-test04.yaml
kubectl get po
# 进入容器查看
kubectl exec -it cm-pod-test004 -c cm-test4 -- bash
root@cm-pod-test004:/usr/local/tomcat# ls /conf
# 3.4 Kubernetes 集群安全机制
# 3.4.1 API-SERVER
Kubernetes api-server 安全访问机制
当我们访问 K8S 集群时,都需要经过 apiserver【 apiserver 做统一协调】,每个请求到达 apiserver 需要经过三个安全关卡: ① 认证
② 鉴权
③ 准入控制
- 访问过程中,需要证书、token、或者用户名和密码
- 如果访问 pod 需要 serviceAccount
(./images/api-server.png)
1、认证
对外不暴露 8080 端口,只能内部访问,对外使用的端口 6443
客户端身份认证常用方式
- https 证书认证,基于 ca 证书
- http token 认证,通过 token 来识别用户
- http 基本认证,用户名 + 密码认证
2、鉴权
基于 RBAC 进行鉴权操作
基于角色访问控制
3、准入控制
就是准入控制器的列表,如果列表有请求内容就通过,没有的话 就拒绝
# 3.4.2 TLS
Kubernetes 认证方式之客户端证书(TLS)
客户端证书(TLS)认证方式,也叫 HTTPS 双向认证。一般我们访问一个 https 网站,认证是单向的,只有客户端会验证服务端的身份,服务端不会管客户端身份如何。
# 3.4.3 RBAC 介绍
Kubernetes 授权方式之 RBAC
基于角色的访问控制,为某个角色设置访问内容,然后用户分配该角色后,就拥有该角色的访问权限
k8s 中有默认的几个角色
- role:特定命名空间访问权限
- ClusterRole:所有命名空间的访问权限
角色绑定
- roleBinding:角色绑定到主体
- ClusterRoleBinding:集群角色绑定到主体
主体
- user:用户
- group:用户组
- serviceAccount:服务账号
# 3.4.4 RBAC 鉴权
1、创建命名空间
# 查看已经存在的命名空间
kubectl get namespace
# 创建自己的命名空间
kubectl create ns mytest
2、命名空间内创建 Pod
如果不创建命名空间,Pod 默认在 default
kubectl run nginx --image=nginx -n mytest
3、创建角色
通过 rbac-role.yaml 进行创建
tips: 这个角色只对 pod 有 get 和 list 权限
cat > rbac-role.yaml << EOF
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: mytest
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
EOF
通过 yaml 创建 role
# 创建
kubectl apply -f rbac-role.yaml
# 查看
kubectl get role -n mytest
4、创建角色绑定
通过 rbac-rolebinding.yaml 的方式,来创建我们的角色绑定
cat > rbac-rolebinding.yaml << EOF
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: mytest
name: read-pods
subjects:
- kind: User
name: lucy
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f rbac-rolebinding.yaml
kubectl get role,rolebinding -n mytest
# NAME CREATED AT
# role.rbac.authorization.k8s.io/pod-reader 2022-01-04T03:05:57Z
# NAME ROLE AGE
# rolebinding.rbac.authorization.k8s.io/read-pods Role/pod-reader 35s
# 4 搭建集群监控平台系统
# 4.1 监控指标
一个好的监控系统主要监控以下内容:
- 集群监控
- 节点资源利用率
- 节点数
- 运行 Pods
- Pod 监控
- 容器指标
- 应用程序【程序占用多少 CPU、内存】
# 4.2 监控平台
- prometheus【监控】
- 定时搜索被监控服务的状态
- 开源
- 监控、报警、数据库
- 以 HTTP 协议周期性抓取被监控组件状态
- 不需要复杂的集成过程,使用 http 接口接入即可
- Grafana【展示】
- 开源的数据分析和可视化工具
- 支持多种数据源
监控平台架构图
(./images/ 监控架构.png)
# 4.3 部署 Pormetheus
# 4.3.1 node-exporter
vim node-exporter.yaml
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: kube-system
labels:
k8s-app: node-exporter
spec:
selector:
matchLabels:
k8s-app: node-exporter
template:
metadata:
labels:
k8s-app: node-exporter
spec:
containers:
- image: prom/node-exporter
name: node-exporter
ports:
- containerPort: 9100
protocol: TCP
name: http
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: node-exporter
name: node-exporter
namespace: kube-system
spec:
ports:
- name: http
port: 9100
nodePort: 31672
protocol: TCP
type: NodePort
selector:
k8s-app: node-exporter
# 4.3.2 rbac
vim rbac-setup.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/proxy
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups:
- extensions
resources:
- ingresses
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: kube-system
# 4.3.3 ConfigMap
vim configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: kube-system
data:
prometheus.yml: |
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'kubernetes-apiservers'
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
action: keep
regex: default;kubernetes;https
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics
- job_name: 'kubernetes-cadvisor'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
- job_name: 'kubernetes-service-endpoints'
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: kubernetes_name
- job_name: 'kubernetes-services'
kubernetes_sd_configs:
- role: service
metrics_path: /probe
params:
module: [http_2xx]
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
action: keep
regex: true
- source_labels: [__address__]
target_label: __param_target
- target_label: __address__
replacement: blackbox-exporter.example.com:9115
- source_labels: [__param_target]
target_label: instance
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_service_name]
target_label: kubernetes_name
- job_name: 'kubernetes-ingresses'
kubernetes_sd_configs:
- role: ingress
relabel_configs:
- source_labels: [__meta_kubernetes_ingress_annotation_prometheus_io_probe]
action: keep
regex: true
- source_labels: [__meta_kubernetes_ingress_scheme,__address__,__meta_kubernetes_ingress_path]
regex: (.+);(.+);(.+)
replacement: ${1}://${2}${3}
target_label: __param_target
- target_label: __address__
replacement: blackbox-exporter.example.com:9115
- source_labels: [__param_target]
target_label: instance
- action: labelmap
regex: __meta_kubernetes_ingress_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_ingress_name]
target_label: kubernetes_name
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
# 4.3.4 Deployment
vim prometheus.deploy.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
name: prometheus-deployment
name: prometheus
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
containers:
- image: prom/prometheus:v2.0.0
name: prometheus
command:
- "/bin/prometheus"
args:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention=24h"
ports:
- containerPort: 9090
protocol: TCP
volumeMounts:
- mountPath: "/prometheus"
name: data
- mountPath: "/etc/prometheus"
name: config-volume
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 500m
memory: 2500Mi
serviceAccountName: prometheus
volumes:
- name: data
emptyDir: {}
- name: config-volume
configMap:
name: prometheus-config
# 4.3.5 Service
vim prometheus.svc.yaml
---
kind: Service
apiVersion: v1
metadata:
labels:
app: prometheus
name: prometheus
namespace: kube-system
spec:
type: NodePort
ports:
- port: 9090
targetPort: 9090
nodePort: 30003
selector:
app: prometheus
# 4.3.6 Create
kubectl create -f node-exporter.yaml
kubectl create -f rbac-setup.yaml
kubectl create -f configmap.yaml
kubectl create -f prometheus.deploy.yml
kubectl create -f prometheus.svc.yml
# 4.3.7 Get
kubectl get pod,svc -n kube-system | grep prometheus
# pod/prometheus-7486bf7f4b-nv2t5 1/1 Running 0 20m
# service/prometheus NodePort 10.102.173.197 <none> 9090:30003/TCP 20m
# 浏览器访问:[ip:port] 192.168.60.151:30003
# 4.4 部署 Grafana
# 4.4.1 Deployment
vim grafana-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: grafana-core
namespace: kube-system
labels:
app: grafana
component: core
spec:
replicas: 1
selector:
matchLabels:
app: grafana
component: core
template:
metadata:
labels:
app: grafana
component: core
spec:
containers:
- image: grafana/grafana:4.2.0
name: grafana-core
imagePullPolicy: IfNotPresent
# env:
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 100m
memory: 100Mi
requests:
cpu: 100m
memory: 100Mi
env:
# The following env variables set up basic auth twith the default admin user and admin password.
- name: GF_AUTH_BASIC_ENABLED
value: "true"
- name: GF_AUTH_ANONYMOUS_ENABLED
value: "false"
# - name: GF_AUTH_ANONYMOUS_ORG_ROLE
# value: Admin
# does not really work, because of template variables in exported dashboards:
# - name: GF_DASHBOARDS_JSON_ENABLED
# value: "true"
readinessProbe:
httpGet:
path: /login
port: 3000
# initialDelaySeconds: 30
# timeoutSeconds: 1
volumeMounts:
- name: grafana-persistent-storage
mountPath: /var
volumes:
- name: grafana-persistent-storage
emptyDir: {}
# 4.4.2 Service
vim grafana-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: grafana
namespace: kube-system
labels:
app: grafana
component: core
spec:
type: NodePort
ports:
- port: 3000
selector:
app: grafana
component: core
# 4.4.3 Runing
vim grafana-ing.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: grafana
namespace: kube-system
spec:
rules:
- host: k8s.grafana
http:
paths:
- path: /
backend:
serviceName: grafana
servicePort: 3000
# 4.4.4 Creat
kubectl create -f grafana-deploy.yaml
kubectl create -f grafana-svc.yaml
kubectl create -f grafana-ing.yaml
# 4.4.5 Get
kubectl get pod,svc -n kube-system | grep grafana
# pod/grafana-core-768b6bf79c-lmq9z 1/1 Running 0 35m
# service/grafana NodePort 10.99.106.133 <none> 3000:32389/TCP 35m
# 浏览器访问:[ip:port] http://192.168.60.151:32389/
# 用户名/密码:admin/admin
登录
![]
添加数据源 Prometheus
展示
# 5 从零搭建高可用 Kubernetes 集群
之前我们搭建的集群,只有一个 master 节点,当 master 节点宕机的时候,通过 node 节点将无法继续访问,而 master 主要是管理作用,所以整个集群将无法提供服务。
# 5.1 高可用集群架构
- 在 node 节点和 master 节点之间,需要一个 LoadBalancer 组件
- 【作用 1】负载
- 【作用 2】检查 master 节点的状态
- 对外需要一个统一的 VIP
- 【作用 1】虚拟 ip 对外进行访问
# 5.2 高可用集群技术细节
- keepalived:配置虚拟 ip,检查节点的状态
- haproxy:负载均衡服务【类似于 nginx】
- apiserver
- controller
- manager
- scheduler
# 5.3 高可用集群搭建
我们采用 2 个 master 节点,一个 node 节点来搭建高可用集群。
# 5.3.1 安装步骤
使用二进制包方式搭建 Kubernetes 集群主要分为以下几步:
- 【环境准备】准备四台虚拟机,并安装操作系统 CentOS 7.x
- 【系统初始化】对四个刚安装好的操作系统进行初始化操作
- 【安装 docker、kubectl、kubeadm、kubectl】对四个节点进行安装
- 【配置高可用 VIP】对 master 节点安装
keepalived
和haproxy
- 【部署 master 组件】在 master 节点上安装
kube-apiserver
、kube-controller-manager
、kube-scheduler
- 【安装网络插件】配置 CNI 网络插件,用于节点之间的连通
- 【测试集群】通过拉取一个 nginx 进行测试,能否进行外网测试
# 5.3.2 安装要求
在开始之前,部署 Kubernetes 集群机器需要满足以下几个条件:
- 一台或多台机器,操作系统 CentOS7.x-86_x64
- 硬件配置:2GB 或更多 RAM,2 个 CPU 或更多 CPU,硬盘 30GB 或更多 **【注意】【注意】【注意】【master 需要两核】**
- 可以访问外网,需要拉取镜像,如果服务器不能上网,需要提前下载镜像并导入节点
- 禁止 swap 分区
# 5.3.3 准备环境
角色 | IP | 配置 | 步骤 |
---|---|---|---|
k8sLoadBalancer | 192.168.60.150 | 2CPU 1G | init docker kubectl kubeadm kubectl |
k8smaster1 | 192.168.60.151 | 2CPU 2G | init docker kubectl kubeadm kubectl keepalived haproxy |
k8smaster2 | 192.168.60.152 | 2CPU 2G | init docker kubectl kubeadm kubectl keepalived haproxy |
k8snode1 | 192.168.60.153 | 2CPU 2G | init docker kubectl kubeadm kubectl |
# 5.3.4 系统初始化
# 关闭防火墙
systemctl stop firewalld
# 禁用firewalld服务
systemctl disable firewalld
# 关闭selinux
# 临时关闭【立即生效】告警,不启用,Permissive,查看使用 getenforce 命令
setenforce 0
# 永久关闭【重启生效】
sed -i 's/SELINUX=enforcing/\SELINUX=disabled/' /etc/selinux/config
# 关闭swap
# 临时关闭【立即生效】查看使用 free 命令
swapoff -a
# 永久关闭【重启生效】
sed -ri 's/.*swap.*/#&/' /etc/fstab
# 在主机名静态查询表中添加4台主机
cat >> /etc/hosts << EOF
192.168.60.150 k8sLoadBalancer
192.168.60.151 k8smaster1
192.168.60.152 k8smaster2
192.168.60.153 k8snode1
EOF
# 将桥接的IPv4流量传递到iptables的链【3个节点上都执行】
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
# 生效
sysctl --system
# 时间同步
yum install ntpdate -y
ntpdate time.windows.com
# 根据规划设置主机名【k8sLoadBalancer节点上操作】
hostnamectl set-hostname k8sLoadBalancer
# 根据规划设置主机名【k8smaster1节点上操作】
hostnamectl set-hostname ks8master1
# 根据规划设置主机名【k8smaster2节点上操作】
hostnamectl set-hostname k8smaster2
# 根据规划设置主机名【k8snode1节点操作】
hostnamectl set-hostname k8snode1
# 5.3.5 安装 docker、kubelet、kubeadm、kubectl
所有节点安装 docker/kubelet/kubeadm/kubectl,Kubernetes 默认 CRI(容器运行时)为 docker,因此先安装 docker
1、安装 docker
(1)首先配置一下 docker 的阿里 yum 源
cat >/etc/yum.repos.d/docker.repo<<EOF
[docker-ce-edge]
name=Docker CE Edge - \$basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/\$basearch/edge
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF
(2)然后 yum 方式安装 docker
# yum安装
yum -y install docker-ce
# 查看docker版本
docker --version
(3)配置 docker 的镜像源【阿里云】
cat >> /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
(4)然后启动 docker
systemctl start docker
systemctl enable docker
systemctl status docker
2、安装 kubeadm,kubelet 和 kubectl
(1)配置 kubernetes 阿里云 yum 源
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)yum 方式安装,由于版本更新频繁,这里指定版本号部署
# 查看版本
yum list kubeadm --showduplicates
# 安装kubelet、kubeadm、kubectl,同时指定版本
yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
# 设置开机启动【这里先不启动】
systemctl enable kubelet
# 5.3.6 配置高可用 VIP【haproxy+keepalived】
【k8smaster1 + k8smaster2 上操作】
1、安装 haproxy + keepalived
我们需要在所有的 master 节点【k8smaster1 和 k8smaster2】上部署 haproxy + keepAlive
yum install -y haproxy keepalived
2、配置 haproxy
所有
master
节点的haproxy
配置相同,haproxy 的配置文件是/etc/haproxy/haproxy.cfg
配置中声明了后端代理的两个 master 节点服务器,指定了 haproxy 运行的端口为 16443 等,因此 16443 端口为集群的入口
cat > /etc/haproxy/haproxy.cfg << EOF
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
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
#---------------------------------------------------------------------
# kubernetes apiserver frontend which proxys to the backends
#---------------------------------------------------------------------
frontend kubernetes-apiserver
mode tcp
bind *:16443
option tcplog
default_backend kubernetes-apiserver
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend kubernetes-apiserver
mode tcp
balance roundrobin
server k8smaster1 192.168.60.151:6443 check
server k8smaster2 192.168.60.152:6443 check
#---------------------------------------------------------------------
# collection haproxy statistics message
#---------------------------------------------------------------------
listen stats
bind *:10080
stats auth admin:awesomePassword
stats refresh 5s
stats realm HAProxy\ Statistics
stats uri /admin?stats
EOF
3、配置 keepalived
keepalived
中使用track_script
机制来配置脚本进行探测kubernetes
的master
节点是否宕机,并以此切换节点实现高可用。
(1) k8smaster1
节点的 keepalived
配置文件如下所示,配置文件所在的位置 /etc/keepalived/keepalived.cfg
。
cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
router_id k8s
}
vrrp_script check_haproxy {
script "killall -0 haproxy"
interval 3
weight -2
fall 10
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface ens33
mcast_src_ip 192.168.60.151
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass ceb1b3ec013d66163d6ab
}
virtual_ipaddress {
192.168.60.150
}
track_script {
check_haproxy
}
}
EOF
需要注意几点(前两点记得修改):
mcast_src_ip
:配置多播源地址,此地址是当前主机的 ip 地址。priority
:keepalived
根据此项参数的大小仲裁master
节点。我们这里让 master 节点为kubernetes
提供服务,其他两个节点暂时为备用节点。因此k8smaster1
节点设置为100
,k8smaster2
节点设置为99
。state
:我们将k8smaster1
节点的state
字段设置为MASTER
,其他节点字段修改为BACKUP
。- 上面的集群检查功能是关闭的,等到集群建立完成后再开启。
(2)配置 k8smaster2 节点
cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
router_id k8s
}
vrrp_script check_haproxy {
script "killall -0 haproxy"
interval 3
weight -2
fall 10
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
mcast_src_ip 192.168.60.152
virtual_router_id 51
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass ceb1b3ec013d66163d6ab
}
virtual_ipaddress {
192.168.60.150
}
track_script {
check_haproxy
}
}
EOF
4、启动和检查 【k8smaster1 和 k8smaster2 均要启动】
# 启动 haproxy
systemctl start haproxy
systemctl enable haproxy
systemctl status haproxy
# 启动keepalived
systemctl start keepalived.service
systemctl enable keepalived.service
systemctl status keepalived.service
# 启动后查看master网卡信息
ip a s ens33
# 检查是否可以ping通
ping 192.168.60.150
# 如果出错
# 初始化一下!!!并重新启动!!!
systemctl stop firewalld
setenforce 0
swapoff -a
# 5.3.7 部署 Kubernetes Master 组件
【k8smaster1 + k8smaster2 + k8snode1 上操作】
1、 k8smaster1
节点
(1)初始化操作
# 导出初始化配置文件,然后修改配置,再进行初始化
kubeadm config print init-defaults > kubeadm-init.yaml
# 这里直接写入配置,并初始化
cat > kubeadm-init.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.60.150 # k8sLoadBalancer ip
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: k8sloadbalancer
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
---
apiServer: # 添加两行配置
certSANs:
- "192.168.60.150" # k8sLoadBalancer ip 即VIP的地址
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers # 阿里云的镜像站点
controlPlaneEndpoint: "192.168.60.150:16443" # VIP的地址和端口
kind: ClusterConfiguration
kubernetesVersion: v1.18.0
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16 # 添加pod网段
scheduler: {}
EOF
# 直接kubeadm init初始化,中间会拉取镜像,速度较慢,分为两步来做
# (1)提前拉取镜像
kubeadm config images pull --config kubeadm-init.yaml
# (2)初始化
kubeadm init --config kubeadm-init.yaml --upload-certs
####### 初始化结果 ########
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join 192.168.60.150:16443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:68d59df77d9109c44a60a8ca4e7f0932d8cd270c5d0a8adc83c9a1a7d72de73a \
--control-plane --certificate-key b84d54cf9015ef8252e38d68ae96be4b7e41fc9380d8dc2b9ac9ae916b0e9cda
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.60.150:16443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:68d59df77d9109c44a60a8ca4e7f0932d8cd270c5d0a8adc83c9a1a7d72de73a
(2)按照提示信息,执行下方命令
# 执行下方命令
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 查看节点
kubectl get nodes
# 查看pod
kubectl get pods -n kube-system
## 输出结果
[root@ks8master1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8sloadbalancer NotReady master 3m58s v1.18.0
[root@ks8master1 ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-546565776c-skjzz 0/1 Pending 0 3m50s
coredns-546565776c-xm8wf 0/1 Pending 0 3m50s
etcd-k8sloadbalancer 1/1 Running 0 4m5s
kube-apiserver-k8sloadbalancer 1/1 Running 0 4m5s
kube-controller-manager-k8sloadbalancer 1/1 Running 0 4m5s
kube-proxy-gbjmm 1/1 Running 0 3m48s
kube-scheduler-k8sloadbalancer 1/1 Running 0 4m5s
2、 k8smaster2
节点
按照 k8smaster1
提示信息,将 k8smaster2
加入集群
# k8smaster2加入集群
kubeadm join 192.168.60.150:16443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:68d59df77d9109c44a60a8ca4e7f0932d8cd270c5d0a8adc83c9a1a7d72de73a \
--control-plane --certificate-key b84d54cf9015ef8252e38d68ae96be4b7e41fc9380d8dc2b9ac9ae916b0e9cda
# 查看集群状态
kubectl get cs
# 查看pod
kubectl get pods -n kube-system
3、 k8snode1
节点
按照 k8smaster1
提示信息,将 k8snode1
加入集群
kubeadm join 192.168.60.150:16443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:68d59df77d9109c44a60a8ca4e7f0932d8cd270c5d0a8adc83c9a1a7d72de73a
# 5.3.8 安装集群网络
从官方地址获取到 flannel 的 yaml,在 k8smaster1 上执行
# 下载yaml文件
wget -c https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 安装flannel网络
kubectl apply -f kube-flannel.yml
# 检查
kubectl get pods -n kube-system
## 可以看到kube-flannel正在安装
[root@ks8master1 ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-546565776c-skjzz 0/1 Pending 0 21m
coredns-546565776c-xm8wf 0/1 Pending 0 21m
etcd-k8sloadbalancer 1/1 Running 2 21m
etcd-k8smaster2 1/1 Running 0 7m58s
kube-apiserver-k8sloadbalancer 1/1 Running 3 21m
kube-apiserver-k8smaster2 1/1 Running 1 7m58s
kube-controller-manager-k8sloadbalancer 1/1 Running 2 21m
kube-controller-manager-k8smaster2 1/1 Running 1 7m58s
kube-flannel-ds-cv84g 0/1 Init:1/2 0 91s
kube-flannel-ds-j9mbn 0/1 Init:1/2 0 91s
kube-flannel-ds-qplqm 0/1 Init:1/2 0 91s
kube-proxy-gbjmm 1/1 Running 0 21m
kube-proxy-qqdl5 1/1 Running 0 13m
kube-proxy-s8bvq 1/1 Running 0 6m27s
kube-scheduler-k8sloadbalancer 1/1 Running 2 21m
kube-scheduler-k8smaster2 1/1 Running 1 7m58s
# 5.3.9 测试 kubernetes 集群
在 Kubernetes 集群中创建一个 pod,验证是否正常运行:
# 创建nginx deployment
kubectl create deployment nginx --image=nginx
# 暴露端口
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看状态
kubectl get pod,svc
## [ip:port]
# 浏览器访问:
# 192.168.60.151:32594
# 192.168.60.152:32594
# 192.168.60.153:32594
[root@ks8master1 ~]# kubectl get pod,svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24m
service/nginx NodePort 10.109.174.226 <none> 80:32594/TCP 8s
然后我们通过任何一个节点,都能够访问我们的 nginx 页面。
# 6 在集群环境中部署项目
在 Kubernetes 集群中部署 Java 项目
# 6.1 容器交付流程
- 开发代码阶段
- 编写代码
- 编写 Dockerfile【打镜像做准备】
- 持续交付 / 集成
- 代码编译打包
- 制作镜像
- 上传镜像仓库
- 应用部署
- 环境准备
- Pod
- Service
- Ingress
- 运维
- 监控
- 故障排查
- 应用升级
# 6.2 k8s 部署 java 项目流程
- 制作镜像【Dockerfile】
- 上传到镜像仓库【Dockerhub、阿里云、网易】
- 控制器部署镜像【Deployment】
- 对外暴露应用【Service、Ingress】
- 运维【监控、升级】
# 6.3 k8s 部署 Java 项目
待更新…