1、kubernetes 简介
2、kubernetes 集群搭建
3、kubeadm kubernetes 核心技术
4、部署性能监控平台
5、搭建kubernetes 高可用集群
6、kubernetes 部署项目
kubernetes,简称 K8s,是用 8 代替 8 个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes 提供了应用部署,规划,更新,维护的一种机制。
传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。
新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进行迁移。
容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间 成一对一关系也使容器有更大优势,使用容器可以在 build 或 release 的阶段,为应用创建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,这使得从研发到测试、生产能提供一致环境。类似地,容器比虚拟机轻量、更“透明”, 这更便于监控和管理。
Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡。
在 Kubernetes 中,我们可以创建多个容器,每个容器里面运行一个应用实例,然后通过内置的负载均衡策略,实现对这一组应用实例的管理、发现、访问,而这些细节都不需要运维人员去进行复杂的手工配置和处理。
Kubernetes 是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务。通过 Kubernetes 能够进行应用的自动化部署和扩缩容。在 Kubernetes 中,会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes 积累了作为 Google 生产环境运行工作负载 15 年的经验,并吸收了来自于社区的最佳想法和实践。
(1)自动装箱
基于容器对应用运行环境的资源配置要求自动部署应用容器
(2)自我修复(自愈能力)
当容器失败时,会对容器进行重启
当所部署的 Node 节点有问题时,会对容器进行重新部署和重新调度
当容器未通过监控检查时,会关闭此容器直到容器正常运行时,才会对外提供服务
(3)水平扩展
通过简单的命令、用户 UI 界面或基于 CPU 等资源使用情况,对应用容器进行规模扩大或规模剪裁
(3)服务发现
用户不需使用额外的服务发现机制,就能够基于 Kubernetes 自身能力实现服务发现和负载均衡
(4)滚动更新
可以根据应用的变化,对应用容器运行的应用,进行一次性或批量式更新
(5)版本回退
可以根据应用部署情况,对应用容器运行的应用,进行历史版本即时回退
(6)密钥和配置管理
在不需要重新构建镜像的情况下,可以部署和更新密钥和应用配置,类似热部署。
(7)存储编排
自动实现存储系统挂载及应用,特别对有状态应用实现数据持久化非常重要
存储系统可以来自于本地目录、网络存储(NFS、Gluster、Ceph 等)、公共云存储服务
(8)批处理
提供一次性任务,定时任务;满足批量数据处理和分析的场景
(1) 无中心节点架构
GlusterFS
(2) 有中心节点架构
HDFS
K8S
Master Node
k8s 集群控制节点,对集群进行调度管理,接受集群外用户去集群操作请求;
Master Node 由API Server、Scheduler、ClusterState Store(ETCD 数据库)和Controller MangerServer 所组成。
Worker Node
集群工作节点,运行用户业务应用容器;
Worker Node 包含kubelet、kube proxy 和ContainerRuntime;
目前生产部署Kubernetes 集群主要有两种方式:
(1)kubeadm
Kubeadm 是一个K8s 部署工具,提供kubeadm init 和kubeadm join,用于快速部署Kubernetes 集群。
官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/
(2)二进制包
从github 下载发行版的二进制包,手动部署每个组件,组成Kubernetes 集群。
Kubeadm 降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易可控,推荐使用二进制包部署Kubernetes 集群,虽然手动部署麻烦点,期间可以学习很多工作原理,也利于后期维护。
kubeadm 是官方社区推出的一个用于快速部署kubernetes 集群的工具,这个工具能通过两条指令完成一个kubernetes 集群的部署:
第一、创建一个Master 节点 kubeadm init
第二, 将Node 节点加入到当前集群中 $ kubeadm join
在开始之前,部署Kubernetes 集群机器需要满足以下几个条件:
(1) 在所有节点上安装Docker 和kubeadm
(2)部署Kubernetes Master
(3)部署容器网络插件
(4)部署Kubernetes Node,将节点加入Kubernetes 集群中
(5)部署Dashboard Web 页面,可视化查看Kubernetes 资源
角色 IP
k8s-master 192.168.31.61
k8s-node1 192.168.31.62
k8s-node2 192.168.31.63
6.1 关闭防火墙
$ systemctl stop firewalld
$ systemctl disable firewalld
6.2 关闭selinux
$ sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
$ setenforce 0 # 临时
6.3 关闭swap
$ swapoff -a # 临时
$ vim /etc/fstab # 永久
6.4 主机名
$ hostnamectl set-hostname <hostname>
6.5 在master 添加hosts
$ cat >> /etc/hosts << EOF
192.168.31.61 k8s-master
192.168.31.62 k8s-node1
192.168.31.63 k8s-node2
EOF
6.6 将桥接的IPv4 流量传递到iptables 的链
$ cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sysctl --system # 生效
6.7 时间同步:
$ yum install ntpdate -y
$ ntpdate time.windows.com
Kubernetes 默认CRI(容器运行时)为Docker,因此先安装Docker。
(1)安装Docker
$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
$ yum -y install docker-ce-18.06.1.ce-3.el7
$ systemctl enable docker && systemctl start docker
$ docker --version
(2)添加阿里云YUM 软件源
# cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
$ 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
(3)安装kubeadm,kubelet 和kubectl
$ yum install -y kubelet kubeadm kubectl
$ systemctl enable kubelet
(1)在192.168.31.61(Master)执行
$ kubeadm init \
--apiserver-advertise-address=192.168.31.61 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.17.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16
由于默认拉取镜像地址k8s.gcr.io 国内无法访问,这里指定阿里云镜像仓库地址。
(2)使用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
$ kubectl apply –f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kubeflannel.yml
确保能够访问到quay.io 这个registery。如果Pod 镜像下载失败,可以改这个镜像地址
(1)在192.168.31.62/63(Node)执行
向集群添加新节点,执行在kubeadm init 输出的kubeadm join 命令:
$ kubeadm join 192.168.31.61:6443 --token esce21.q6hetwm8si29qxwn \
--discovery-token-ca-cert-hash
sha256:00603a05805807501d7181c3d60b478788408cfe6cedefedb1f97569708be9c5
在Kubernetes 集群中创建一个pod,验证是否正常运行:
$ kubectl create deployment nginx --image=nginx
$ kubectl expose deployment nginx --port=80 --type=NodePort
$ kubectl get pod,svc
访问地址:http://NodeIP:Port
在开始之前,部署Kubernetes 集群机器需要满足以下几个条件:
(1)一台或多台机器,操作系统CentOS7.x-86_x64
(2)硬件配置:2GB 或更多RAM,2 个CPU 或更多CPU,硬盘30GB 或更多
(3)集群中所有机器之间网络互通
(4)可以访问外网,需要拉取镜像,如果服务器不能上网,需要提前下载镜像并导入节点
(5)禁止swap 分区
(1)软件环境:
软件 | 版本 |
---|---|
操作系统 | CentOS7.8_x64 (mini) |
Docker | 19-ce |
Kubernetes | 1.19 |
(2)服务器规划:
角色 | IP | 组件 |
---|---|---|
k8s-master | 192.168.31.71 | kube-apiserver,kube-controller-manager,kube-scheduler,etcd |
k8s-node1 | 192.168.31.72 | kubelet,kube-proxy,docker,etcd |
k8s-node2 | 192.168.31.73 | kubelet,kube-proxy,docker,etcd |
# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
# 关闭selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
setenforce 0 # 临时
# 关闭swap
swapoff -a # 临时
sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久
# 根据规划设置主机名
hostnamectl set-hostname <hostname>
# 在master 添加hosts
cat >> /etc/hosts << EOF
192.168.44.147 m1
192.168.44.148 n1
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
sysctl --system # 生效
# 时间同步
yum install ntpdate -y
ntpdate time.windows.com
Etcd 是一个分布式键值存储系统,Kubernetes 使用Etcd 进行数据存储,所以先准备一个Etcd 数据库,为解决Etcd 单点故障,应采用集群方式部署,这里使用3 台组建集群,可容忍1 台机器故障,当然,你也可以使用5 台组建集群,可容忍2 台机器故障。
节点名称 | IP |
---|---|
etcd-1 | 192.168.31.71 |
etcd-2 | 192.168.31.72 |
etcd-3 | 192.168.31.73 |
注:为了节省机器,这里与K8s 节点机器复用。也可以独立于k8s 集群之外部署,只要 apiserver 能连接到就行。
4.1 准备cfssl 证书生成工具
cfssl 是一个开源的证书管理工具,使用 json 文件生成证书,相比openssl 更方便使用。找任意一台服务器操作,这里用Master 节点。
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
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/bin/cfssl-certinfo
4.2 生成Etcd 证书
(1)自签证书颁发机构(CA)
创建工作目录:
mkdir -p ~/TLS/{etcd,k8s}
cd TLS/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",
"ST": "Beijing"
}
]
}
EOF
生成证书:
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
ls *pem
ca-key.pem ca.pem
(2)使用自签CA 签发Etcd HTTPS 证书
创建证书申请文件:
cat > server-csr.json<< EOF
{
"CN": "etcd",
"hosts": [
"192.168.31.71",
"192.168.31.72",
"192.168.31.73"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing"
}
]
}
EOF
注:上述文件hosts 字段中IP 为所有etcd 节点的集群内部通信IP,一个都不能少!为了方便后期扩容可以多写几个预留的IP。
生成证书:
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
server-key.pem server.pem
4.3 从Github 下载二进制文件
下载地址:https://github.com/etcd-io/etcd/releases/download/v3.4.9/etcd-v3.4.9-linux-amd64.tar.gz
4.4 部署Etcd 集群
以下在节点1 上操作,为简化操作,待会将节点1 生成的所有文件拷贝到节点2 和节点3.
(1)创建工作目录并解压二进制包
mkdir /opt/etcd/{bin,cfg,ssl} –p
tar zxvf etcd-v3.4.9-linux-amd64.tar.gz
mv etcd-v3.4.9-linux-amd64/{etcd,etcdctl} /opt/etcd/bin/
(2)创建etcd 配置文件
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.31.71:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.31.71:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.31.71:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.31.71:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.31.71:2380,etcd-
2=https://192.168.31.72:2380,etcd-3=https://192.168.31.73: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 表示加入已有集群
(3)systemd 管理etcd
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
(4)拷贝刚才生成的证书
把刚才生成的证书拷贝到配置文件中的路径:
cp ~/TLS/etcd/ca*pem ~/TLS/etcd/server*pem /opt/etcd/ssl/
(5)启动并设置开机启动
systemctl daemon-reload
systemctl start etcd
systemctl enable etcd
(6)将上面节点1 所有生成的文件拷贝到节点2 和节点3
scp -r /opt/etcd/ [email protected]:/opt/
scp /usr/lib/systemd/system/etcd.service [email protected]:/usr/lib/systemd/system/
scp -r /opt/etcd/ [email protected]:/opt/
scp /usr/lib/systemd/system/etcd.service [email protected]:/usr/lib/systemd/system/
然后在节点2 和节点3 分别修改etcd.conf 配置文件中的节点名称和当前服务器IP:
vi /opt/etcd/cfg/etcd.conf
#[Member]
ETCD_NAME="etcd-1" # 修改此处,节点2 改为etcd-2,节点3 改为etcd-3
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.31.71:2380" # 修改此处为当前服务器IP
ETCD_LISTEN_CLIENT_URLS="https://192.168.31.71:2379" # 修改此处为当前服务器IP
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.31.71:2380" # 修改此处为当前服务器IP
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.31.71:2379" # 修改此处为当前服务器IP
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.31.71:2380,etcd-2=https://192.168.31.72:2380,etcd-3=https://192.168.31.73:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
最后启动etcd 并设置开机启动,同上。
(7)查看集群状态
ETCDCTL_API=3 /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.31.71:2379,https://192.168.31.72:2379,https://192.16
8.31.73:2379" endpoint health
https://192.168.31.71:2379 is healthy: successfully committed proposal: took = 8.154404ms
https://192.168.31.73:2379 is healthy: successfully committed proposal: took = 9.044117ms
https://192.168.31.72:2379 is healthy: successfully committed proposal: took = 10.000825ms
如果输出上面信息,就说明集群部署成功。如果有问题第一步先看日志:
/var/log/message 或journalctl -u etcd
下载地址:https://download.docker.com/linux/static/stable/x86_64/docker-19.03.9.tgz
以下在所有节点操作。这里采用二进制安装,用yum 安装也一样。
(1)解压二进制包
tar zxvf docker-19.03.9.tgz
mv docker/* /usr/bin
(2) 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
(3)创建配置文件
mkdir /etc/docker
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
registry-mirrors 阿里云镜像加速器
(4)启动并设置开机启动
systemctl daemon-reload
systemctl start docker
systemctl enable docker
6.1 生成kube-apiserver 证书
(1)自签证书颁发机构(CA)
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
(2)生成证书:
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
ls *pem
ca-key.pem ca.pem
(3)使用自签CA 签发kube-apiserver HTTPS 证书
创建证书申请文件:
cd TLS/k8s
cat > server-csr.json<< EOF
{
"CN": "kubernetes",
"hosts": [
"10.0.0.1",
"127.0.0.1",
"192.168.31.71",
"192.168.31.72",
"192.168.31.73",
"192.168.31.74",
"192.168.31.81",
"192.168.31.82",
"192.168.31.88",
"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
生成证书:
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
server-key.pem server.pem
6.2 从Github 下载二进制文件
下载地址:
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md#v1183
注:打开链接你会发现里面有很多包,下载一个server 包就够了,包含了Master 和Worker Node 二进制文件。
6.3 解压二进制包
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/
6.4 部署kube-apiserver
1. 创建配置文件
cat > /opt/kubernetes/cfg/kube-apiserver.conf << EOF
KUBE_APISERVER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--etcdservers=
https://192.168.31.71:2379,https://192.168.31.72:2379,https://192.168.3
1.73:2379 \\
--bind-address=192.168.31.71 \\
--secure-port=6443 \\
--advertise-address=192.168.31.71 \\
--allow-privileged=true \\
--service-cluster-ip-range=10.0.0.0/24 \\
--enable-admissionplugins=
NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestric
tion \\
--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:nodebootstrapper"
EOF
格式:token,用户名,UID,用户组
token 也可自行生成替换:
head -c 16 /dev/urandom | od -An -t x | tr -d ' '
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
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap
6.5 部署kube-controller-manager
1. 创建配置文件
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 保持一致
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
6.6 部署kube-scheduler
1. 创建配置文件
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
kubectl get cs
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-2 Healthy {"health":"true"}
etcd-1 Healthy {"health":"true"}
etcd-0 Healthy {"health":"true"}
如上输出说明Master 节点组件运行正常。
下面还是在Master Node 上操作,即同时作为Worker Node
7.1 创建工作目录并拷贝二进制文件
在所有worker node 创建工作目录:
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
从master 节点拷贝:
cd kubernetes/server/bin
cp kubelet kube-proxy /opt/kubernetes/bin # 本地拷贝
7.2 部署kubelet
1. 创建配置文件
cat > /opt/kubernetes/cfg/kubelet.conf << EOF
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--hostname-override=k8s-master \\
--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
KUBE_APISERVER="https://192.168.31.71:6443" # apiserver IP:PORT
TOKEN="c47ffb939f5ca36231d9e3121a252940" # 与token.csv 里保持一致
# 生成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
拷贝到配置文件路径:
cp bootstrap.kubeconfig /opt/kubernetes/cfg
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
7.3 批准kubelet 证书申请并加入集群
# 查看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
7.4 部署kube-proxy
1. 创建配置文件
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: k8s-master
clusterCIDR: 10.0.0.0/24
EOF
# 切换工作目录
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
ls kube-proxy*pem
kube-proxy-key.pem kube-proxy.pem
生成kubeconfig 文件:
KUBE_APISERVER="https://192.168.31.71: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
拷贝到配置文件指定路径:
cp kube-proxy.kubeconfig /opt/kubernetes/cfg/
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
7.5 部署CNI 网络
先准备好CNI 二进制文件:
下载地址:
https://github.com/containernetworking/plugins/releases/download/v0.8.6/cniplugins-linux-amd64-v0.8.6.tgz
解压二进制包并移动到默认工作目录:
mkdir /opt/cni/bin
tar zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin
部署CNI 网络:
wget
https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kubeflannel.yml
sed -i -r "s#quay.io/coreos/flannel:.*-amd64#lizhenliang/flannel:v0.12.0-amd64#g" kube-flannel.yml
默认镜像地址无法访问,修改为docker hub 镜像仓库。
kubectl apply -f kube-flannel.yml
kubectl get pods -n kube-system
kubectl get node
部署好网络插件,Node 准备就绪。
7.6 授权apiserver 访问kubelet
cat > apiserver-to-kubelet-rbac.yaml<< EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
- pods/log
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubernetes
EOF
kubectl apply -f apiserver-to-kubelet-rbac.yaml
7.7 新增加Worker Node
1. 拷贝已部署好的Node 相关文件到新节点
在master 节点将Worker Node 涉及文件拷贝到新节点192.168.31.72/73
scp -r /opt/kubernetes [email protected]:/opt/
scp -r /usr/lib/systemd/system/{kubelet,kube-proxy}.service
[email protected]:/usr/lib/systemd/system
scp -r /opt/cni/ [email protected]:/opt/
scp /opt/kubernetes/ssl/ca.pem [email protected]:/opt/kubernetes/ssl
rm /opt/kubernetes/cfg/kubelet.kubeconfig
rm -f /opt/kubernetes/ssl/kubelet*
注:这几个文件是证书申请审批后自动生成的,每个Node 不同,必须删除重新生成。
vi /opt/kubernetes/cfg/kubelet.conf
--hostname-override=k8s-node1
vi /opt/kubernetes/cfg/kube-proxy-config.yml
hostnameOverride: k8s-node1
systemctl daemon-reload
systemctl start kubelet
systemctl enable kubelet
systemctl start kube-proxy
systemctl enable kube-proxy
kubectl get csr
NAME AGE SIGNERNAME
REQUESTOR CONDITION
node-csr-4zTjsaVSrhuyhIGqsefxzVoZDCNKei-aE2jyTP81Uro 89s
kubernetes.io/kube-apiserver-client-kubelet kubelet-bootstrap Pending
kubectl certificate approve node-csr-4zTjsaVSrhuyhIGqsefxzVoZDCNKeiaE2jyTP81Uro
Kubectl get node
Node2(192.168.31.73 )节点同上。记得修改主机名!
k8s 集群中对资源管理和资源对象编排部署都可以通过声明样式(YAML)文件来解决,也就是可以把需要对资源对象操作编辑到YAML 格式文件中,我们把这种文件叫做资源清单文件,通过kubectl 命令直接使用资源清单文件就可以实现对大量的资源对象进行编排部署了。
(1)YAML 介绍
YAML :仍是一种标记语言。为了强调这种语言以数据做为中心,而不是以标记语言为重点。
YAML 是一个可读性高,用来表达数据序列的格式。
(2)YAML 基本语法
* 使用空格做为缩进
* 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
* 低版本缩进时不允许使用Tab 键,只允许使用空格
* 使用#标识注释,从这个字符一直到行尾,都会被解释器忽略
(3)YAML 支持的数据结构
* 对象
键值对的集合,又称为映射(mapping) / 哈希(hashes) / 字典(dictionary)
* 数组:
一组按次序排列的值,又称为序列(sequence) / 列表(list)
* 纯量(scalars):
单个的、不可再分的值
(1)在k8s 中,一般使用YAML 格式的文件来创建符合我们预期期望的pod,这样的YAML文件称为资源清单。
(2)常用字段
* 必须存在的属性
* spec 主要对象
kubectl 是Kubernetes 集群的命令行工具,通过kubectl 能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。
(1)comand:指定要对资源执行的操作,例如create、get、describe 和delete
(2)TYPE:指定资源类型,资源类型是大小写敏感的,开发者能够以单数、复数和缩略的形式。例如:
(3)NAME:指定资源的名称,名称也大小写敏感的。如果省略名称,则会显示所有的资源,例如:
(2)flags:指定可选的参数。例如,可用-s 或者–server 参数指定Kubernetes API server 的地址和端口。
Pod 是k8s 系统中可以创建和管理的最小单元,是资源对象模型中由用户创建或部署的最小资源对象模型,也是在k8s 上运行容器化应用的资源对象,其他的资源对象都是用来支撑或者扩展Pod 对象功能的,比如控制器对象是用来管控Pod 对象的,Service 或者 Ingress 资源对象是用来暴露Pod 引用对象的,PersistentVolume 资源对象是用来为Pod 提供存储等等,k8s 不会直接处理容器,而是Pod,Pod 是由一个或多个container 组成。
Pod 是Kubernetes 的最重要概念,每一个Pod 都有一个特殊的被称为“根容器”的 Pause 容器。Pause 容器对应的镜像属于Kubernetes 平台的一部分,除了Pause 容器,每个Pod 还包含一个或多个紧密相关的用户业务容器。
(1)Pod vs 应用
每个Pod 都是应用的一个实例,有专用的IP
(2)Pod vs 容器
一个Pod 可以有多个容器,彼此间共享网络和存储资源,每个Pod 中有一个Pause 容器保存所有的容器状态, 通过管理pause 容器,达到管理pod 中所有容器的效果
(3)Pod vs 节点
同一个Pod 中的容器总会被调度到相同Node 节点,不同节点间Pod 的通信基于虚拟二层网络技术实现。
(4)Pod vs Pod
普通的Pod 和静态Pod
Pod是在K8S集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。同时Pod对多容器的支持是K8S中最基础的设计理念。在生产环境中,通常是由不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。
Pod是K8S集群中所有业务类型的基础,可以把Pod看作运行在K8S集群上的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前K8S的业务主要可以分为以下几种
上述的几种类型,分别对应的小机器人控制器为:Deployment、Job、DaemonSet 和 StatefulSet (后面将介绍控制器)
(1)资源共享
一个Pod 里的多个容器可以共享存储和网络,可以看作一个逻辑的主机。共享的如namespace,cgroups 或者其他的隔离资源。
多个容器共享同一network namespace,由此在一个Pod 里的多个容器共享Pod 的IP 和端口namespace,所以一个Pod 内的多个容器之间可以通过localhost 来进行通信,所需要注意的是不同容器要注意不要有端口冲突即可。不同的Pod 有不同的IP,不同Pod 内的多个容器之前通信,不可以使用IPC(如果没有特殊指定的话)通信,通常情况下使用Pod 的 IP 进行通信。
一个Pod 里的多个容器可以共享存储卷,这个存储卷会被定义为Pod 的一部分,并且可以挂载到该Pod 里的所有容器的文件系统上。
:::info
主要有以下两大机制
容器本身之间相互隔离的,一般是通过 namespace 和 group 进行隔离,那么Pod里面的容器如何实现通信?
关于Pod实现原理,首先会在Pod会创建一个根容器: pause容器,然后我们在创建业务容器 【nginx,redis 等】,在我们创建业务容器的时候,会把它添加到 info容器 中
而在 info容器 中会独立出 ip地址,mac地址,port 等信息,然后实现网络的共享
完整步骤如下
Pod持久化数据,专门存储到某个地方中
使用 Volumn数据卷进行共享存储,案例如下所示
:::
(2)生命周期短暂
Pod 属于生命周期比较短暂的组件,比如,当Pod 所在节点发生故障,那么该节点上的Pod会被调度到其他节点,但需要注意的是,被重新调度的Pod 是一个全新的Pod,跟之前的 Pod 没有半毛钱关系。
(3)平坦的网络
K8s 集群中的所有Pod 都在同一个共享网络地址空间中,也就是说每个Pod 都可以通过其他Pod 的IP 地址来实现访问。
(1)pod常用的yaml格式定义配置文件说明
apiVersion: v1 #必选,api版本号
kind: Pod #必选,资源对象名称
metadata: #必选,元数据 map类型
name: -pod-name> #必选,pod名称
namespace: -pod-namespace> #默认default,pod所属的命名空间
labels:
name: -labes-name> #自定义的pod标签
spec: #必选,pod中container的详细属性
containers: #必选,pod中容器列表,list类型
- name: -container-name> #必选,容器名称
image: -container-name> #必选,容器镜像
imagePullPolicy: {Always | Never | IfNotPresent} #Always表示下载镜像,Never表示本地镜像,IfNotPresent表示优先使用本地镜像,否则下载
volumeMounts:
- name: -pod-volume-name> #引用pod定义的共享存储卷名
mountPath: -path> #存储卷在容器内Mount的绝对路径
ports: #容器需要暴露的端口列表
- name: -port-name> #需要暴露的端口名称
containerPort: -container-port> #容器需要监听的端口
env: #容器运行前 需要设置的环境变量列表
- name: -env-name> #环境变量的名称
value: -env-value> #环境变量的值
livenessProbe: #对容器进行健康检查
tcpSocket: # 对Pod容器内检查方式设置为tcpSocket方式
port: -container-port> #需要健康检查的端口
initialDelaySeconds: 15 #容器启动十五秒开始发起第一次探针
periodSeconds: 20 #每隔二十秒进行探针一次
readinessProbe:
tcpSocket:
port: -container-port> #需要健康检查的端口
initialDelaySeconds: 5 #容器启动五秒开始发起第一次探针
periodSeconds: 10 #每隔十秒进行探针一次
nodeSelector: #NodeSelector表示将该Pod调度到包含这个label的node上
hostname: k8snode-1 # 调度到指定的标签Node上
volumes:
- name: -volume-name> #共享存储卷名称
emptyDir: { } # 类型为emptyDir的存储卷,与Pod同生命周期的一个临时目录,为空值
hostpath: # 类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: -host-path>
在kubernetes 中对运行容器的要求为:容器的主程序需要一直在前台运行,而不是后台运行。应用需要改造成前台运行的方式。如果我们创建的Docker 镜像的启动命令是后台执行程序,则在kubelet 创建包含这个容器的pod 之后运行完该命令,即认为Pod 已经结束,将立刻销毁该Pod。如果为该Pod 定义了RC,则创建、销毁会陷入一个无限循环的过程中。Pod 可以由1 个或多个容器组合而成。
(1)一个容器组成的Pod 的yaml 示例
一个容器组成的Pod
apiVersion: v1
kind: Pod
metadata:
name: mytomcat
labels:
name: mytomcat
spec:
containers:
- name: mytomcat
image: tomcat
ports:
- containerPort: 8000
(2)多个容器组成的Pod 的yaml 示例
#两个紧密耦合的容器
apiVersion: v1
kind: Pod
metadata:
name: myweb
labels:
name: tomcat-redis
spec:
containers:
-name: tomcat
image: tomcat
ports:
-containerPort: 8080
-name: redis
image: redis
ports:
-containerPort: 6379
(3)创建
kubectl create -f xxx.yaml
(4)查看
kubectl get pod/po <Pod_name>
kubectl get pod/po <Pod_name> -o wide
kubectl describe pod/po <Pod_name>
(5)删除
kubectl delete -f pod pod_name.yaml
kubectl delete pod --all/[pod_name]
Pod 有两种类型
(1)普通Pod
普通Pod 一旦被创建,就会被放入到etcd 中存储,随后会被Kubernetes Master 调度到某个具体的Node 上并进行绑定,随后该Pod 对应的Node 上的kubelet 进程实例化成一组相关的Docker 容器并启动起来。在默认情况下,当Pod 里某个容器停止时,Kubernetes 会自动检测到这个问题并且重新启动这个Pod 里某所有容器, 如果Pod 所在的Node 宕机,则会将这个Node 上的所有Pod 重新调度到其它节点上。
(2)静态Pod
静态Pod 是由kubelet 进行管理的仅存在于特定Node 上的Pod,它们不能通过API Server 进行管理,无法与ReplicationController、Deployment 或DaemonSet 进行关联,并且kubelet 也无法对它们进行健康检查。
:::info
创建Pod流程
(1)Pod 的状态
(2)Pod 重启策略(对容器的重启)
Pod 的重启策略包括Always、OnFailure 和Never,默认值是Always
:::info
因为Pod中包含了很多个容器,假设某个容器出现问题了,那么就会触发Pod重启机制
重启策略主要分为以下三种
每个Pod 都可以对其能使用的服务器上的计算资源设置限额,Kubernetes 中可以设置限额的计算资源有CPU 与Memory 两种,其中CPU 的资源单位为CPU 数量,是一个绝对值而非相对值。Memory 配额也是一个绝对值,它的单位是内存字节数。
Kubernetes 里,一个计算资源进行配额限定需要设定以下两个参数: Requests 该资源最小申请数量,系统必须满足要求Limits 该资源最大允许使用的量,不能突破,当容器试图使用超过这个量的资源时,可能会被Kubernetes Kill 并重启。
(1)举例
sepc:
containers:
- name: db
image: mysql
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
上述代码表明MySQL 容器申请最少0.25 个CPU 以及64MiB 内存,在运行过程中容器所能使用的资源配额为0.5 个CPU 以及128MiB 内存。
Label 是Kubernetes 系统中另一个核心概念。一个Label 是一个key=value 的键值对,其中key 与value 由用户自己指定。Label 可以附加到各种资源对象上,如Node、Pod、Service、RC,一个资源对象可以定义任意数量的Label, 同一个Label 也可以被添加到任意数量的资源对象上,Label 通常在资源对象定义时确定,也可以在对象创建后动态添加或删除。
Label 的最常见的用法是使用metadata.labels 字段,来为对象添加Label,通过spec.selector 来引用对象。
1.1 Label 含义
Label其实就一对 key/value ,被关联到对象上,比如Pod,标签的使用我们倾向于能够标示对象的特殊特点,Labels的值对系统本身并没有什么含义,只是对用户才有意义。同一个资源对象的labels属性的key必须唯一,label可以附加到各种资源对象上,如Node,Pod,Service,RC等。一个资源拥有多个标签,可以实现不同维度的管理。标签(Label)的组成: key=value。Label可以在创建对象时就附加到对象上,也可以在对象创建后通过API进行额外添加或修改。
1.2 Label命名规范
label 必须以字母或数字开头,可以使用字母、数字、连字符、点和下划线,最长63个字符。
2.1 当相同类型的资源越来越多,对资源划分管理是很有必要,此时就可以使用Label为资源对象 命名,以便于配置,部署等管理工作,提升资源的管理效率。label 作用类似Java包能对不同文件分开管理,让整体更加有条理,有利于维护。
2.2 通过Label来对对象进行引用。
3.1 命令创建
label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]
3.1.1 kubectl get pods 命令默认不会列出任何标签,使用 --show-labels 选项来查看 :
kubectl get po --show-labels
3.1.2 指定标签查看
kubectl get po -L creation_method,env
查看匹配标签条件的node
kubectl get nodes -l 标签key=标签values
kubectl get nodes -l app=tomcat
查看匹配 标签key的pod
kubectl get po -L app
3.1.3 给名为tomcat 的Pod添加label app=tomcat。
kubectl label pods tomcat app=tomcat
3.1.4 把名为tomcat 的Pod修改label 为 app=tomcat1,且覆盖现有的value
kubectl label --overwrite pods tomcat app=tomcat1
3.1.5 把 namespace 中的所有 pod 添加 label
kubectl label pods --all test=test
3.1.6 删除名为“app”的label 。(使用“ - ”减号相连)
kubectl label pods tomcat app-
3.2 yaml脚本创建
vim label-pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: tomcat
labels:
app: tomcat
release: stable
spec:
containers:
- name: tomcat
image: tomcat
ports:
- containerPort: 80
为tomcat的Pod添加了两个Label,分别为app: tomcat和release: tomcat
常用的,多维度标签分类:
版本标签(release): stable(稳定版),canary(金丝雀版本),beta(测试版)
环境类(environment): dev(开发),qa(测试),production(生产),op(运维)
应用类(applaction): ui(设计),as(应用软件),pc(电脑端),sc(网络方面)
架构层(tier): frontend(前端),backend(后端),cache(缓存)
分区标签(partition): customerA(客户),customerB
品控级别(track): daily(每天),weekly(每周)
vim label-pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: label-pod-test
labels: #使用labels字段来定义标签,可以一次定义多个标签,这里定义3个标签
release: stable #版本:稳定版
env: qa #环境:测试
tier: frontend #架构类:前端
spec:
containers:
- name: testTomcatLabel
image: tomcat #部署的是tomcat服务
Replication Controller(RC)是Kubernetes 系统中核心概念之一,当我们定义了一个RC 并提交到Kubernetes 集群中以后,Master 节点上的Controller Manager 组件就得到通知,定期检查系统中存活的Pod,并确保目标Pod 实例的数量刚好等于RC 的预期值,如果有过多或过少的Pod 运行,系统就会停掉或创建一些Pod。此外我们也可以通过修改RC 的副本数量,来实现Pod 的动态缩放功能。
kubectl scale rc nginx --replicas=5
由于Replication Controller 与Kubernetes 代码中的模块Replication Controller 同名,所以在Kubernetes v1.2 时, 它就升级成了另外一个新的概念Replica Sets,官方解释为下一代的RC,它与RC 区别是:Replica Sets 支援基于集合的Label selector,而RC 只支持基于等式的Label Selector。我们很少单独使用Replica Set,它主要被Deployment 这个更高层面的资源对象所使用,从而形成一整套Pod 创建、删除、更新的编排机制。最好
不要越过RC 直接创建Pod, 因为Replication Controller 会通过RC 管理Pod 副本,实现自动创建、补足、替换、删除Pod 副本,这样就能提高应用的容灾能力,减少由于节点崩溃等意外状况造成的损失。即使应用程序只有一个Pod 副本,也强烈建议使用RC 来定义Pod。
ReplicaSet 跟ReplicationController 没有本质的不同,只是名字不一样,并且ReplicaSet 支持集合式的selector(ReplicationController 仅支持等式)。
Kubernetes 官方强烈建议避免直接使用ReplicaSet,而应该通过Deployment 来创建RS 和 Pod。由于ReplicaSet 是ReplicationController 的代替物,因此用法基本相同,唯一的区别在于ReplicaSet 支持集合式的selector。
Deployment是k8s中用来管理发布的控制器,在开发的过程中使用非常频繁。Deployment 是Kubenetes v1.2 引入的新概念,引入的目的是为了更好的解决Pod 的编排问题,Deployment 内部使用了Replica Set 来实现。Deployment 的定义与Replica Set 的定义很类似,除了API 声明与Kind 类型有所区别。
Deployment的作用
主要字段说明
Deployment相关状态
Deployment的控制流程
同样也是通过inform对事件进行list&watch并调用相关的handle进行处理(其中关于Check Paused是对有关于一些Debugger模式下可以只同步replicas而不发布版本。)
而对应RS控制器则更加简单了,只对pod数量进行控制管理就行。相对而言,deployment更加复杂一些,同时能做的事情也更多。
![image.png](https://img-blog.csdnimg.cn/img_convert/5bab30a31c3e6fc10216494090f8ef37.png#clientId=uda32f5ef-619e-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u6e685621&margin=%5Bobject%20Object%5D&name=image.png&originHeight=457&originWidth=1305&originalType=url&ratio=1&rotation=0&showTitle=false&size=235113&status=done&style=none&taskId=ua12a66c7-b0f9-4ef9-887f-41736da131d&title=)
Horizontal Pod Autoscal (Pod 横向扩容简称HPA) 与RC、Deployment 一样,也属于一种Kubernetes 资源对象。通过追踪分析RC 控制的所有目标Pod 的负载变化情况,来确定是否需要针对性地调整目标Pod 的副本数,这是HPA 的实现原理。
Kubernetes 对Pod 扩容与缩容提供了手动和自动两种模式,手动模式通过kubectl scale 命令对一个Deployment/RC 进行Pod 副本数量的设置。自动模式则需要用户根据某个性能指标或者自定义业务指标,并指定Pod 副本数量的范围,系统将自动在这个范围内根据性能指标的变化进行调整。
(1)手动扩容和缩容
kubectl scale deployment frontend --replicas 1
(2)自动扩容和缩容
HPA 控制器基本Master 的kube-controller-manager 服务启动参数–horizontal-podautoscaler-sync-period 定义的时长(默认值为30s),周期性地监测Pod 的CPU 使用率,并在满足条件时对RC 或Deployment 中的Pod 副本数量进行调整,以符合用户定义的平均 Pod CPU 使用率。
apiVersion: extensions/v1beta1 kind: Deployment
metadata:
name: nginx-deployment spec:
replicas: 1 template:
metadata: name: nginx labels:
app: nginx spec:
containers:
- name: nginx image: nginx
resources:
requests:
cpu: 50m ports:
- containerPort: 80
-------------------------------
apiVersion: v1 kind: Service metadata:
name: nginx-svc spec:
ports:
- port: 80 selector:
app: nginx
-----------------------------------
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata:
name: nginx-hpa spec:
scaleTargetRef:
apiVersion: app/v1beta1 kind: Deployment
name: nginx-deployment minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 50
Volume 是Pod 中能够被多个容器访问的共享目录。Kubernetes 的Volume 定义在Pod 上,它被一个Pod 中的多个容器挂载到具体的文件目录下。Volume 与Pod 的生命周期相同,但与容器的生命周期不相关,当容器终止或重启时,Volume 中的数据也不会丢失。要使用 volume,pod 需要指定volume 的类型和内容( 字段),和映射到容器的位置( 字段)。
Kubernetes 支持多种类型的Volume,包括:emptyDir、hostPath、gcePersistentDisk、awsElasticBlockStore、nfs、iscsi、flocker、glusterfs、rbd、cephfs、gitRepo、secret、persistentVolumeClaim、downwardAPI、azureFileVolume、azureDisk、vsphereVolume、Quobyte、PortworxVolume、ScaleIO。emptyDirEmptyDir 类型的volume 创建于pod 被调度到某个宿主机上的时候,而同一个pod 内的容器都能读写EmptyDir 中的同一个文件。一旦这个pod 离开了这个宿主机,EmptyDir 中的数据就会被永久删除。所以目前EmptyDir 类型的volume 主要用作临时空间,比如Web 服务器写日志或者tmp 文件需要的临时目录。
apiVersion: v1 kind: Pod metadata:
name: test-pd spec:
containers:
- image: docker.io/nazarpc/webserver
name: test-container
volumeMounts:
- mountPath: /cache name: cache-volume
volumes:
- name: cache-volume emptyDir: {}
HostPath 属性的volume 使得对应的容器能够访问当前宿主机上的指定目录。例如,需要运行一个访问Docker 系统目录的容器,那么就使用/var/lib/docker 目录作为一个HostDir 类型的volume;或者要在一个容器内部运行CAdvisor,那么就使用/dev/cgroups 目录作为一个HostDir 类型的volume。一旦这个pod 离开了这个宿主机,HostDir 中的数据虽然不会被永久删除,但数据也不会随pod 迁移到其他宿主机上。因此,需要注意的是,
由于各个宿主机上的文件系统结构和内容并不一定完全相同,所以相同pod 的HostDir 可能会在不同的宿主机上表现出不同的行为。yaml 示例如下:
apiVersion: v1 kind: Pod metadata:
name: test-pd spec:
containers:
-image: docker.io/nazarpc/webserver name: test-container
# 指定在容器中挂接路径
volumeMounts:
- mountPath: /test-pd name: test-volume
# 指定所提供的存储卷
volumes:
-name: test-volume # 宿主机上的目录hostPath:
# directory location on host path: /data
NFS 类型volume。允许一块现有的网络硬盘在同一个pod 内的容器间共享。yaml 示例如下:
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind:
Deployment
metadata:
name: redis spec:
selector: matchLabels:
app: redis revisionHistoryLimit: 2 template:
metadata:
labels:
app: redis spec:
containers:
# 应用的镜像
-image: redis name: redis
imagePullPolicy: IfNotPresent # 应用的内部端口
ports:
-containerPort: 6379 name: redis6379
env:
-name: ALLOW_EMPTY_PASSWORD
value: "yes"
-name: REDIS_PASSWORD
value: "redis"
# 持久化挂接位置,在docker 中
volumeMounts:
-name: redis-persistent-storage mountPath: /data
volumes:
# 宿主机上的目录
-name: redis-persistent-storage nfs:
path: /k8s-nfs/redis/data server: 192.168.126.112
管理存储是管理计算的一个明显问题。该PersistentVolume 子系统为用户和管理员提供了一个API,用于抽象如何根据消费方式提供存储的详细信息。为此,我们引入了两个新的API 资源:PersistentVolume 和PersistentVolumeClaim。
**PersistentVolume(PV)**是集群中由管理员配置的一段网络存储。它是集群中的资源,就像节点是集群资源一样。PV 是容量插件,如Volumes,但其生命周期独立于使用PV 的任何单个pod。此API 对象捕获存储实现的详细信息,包括NFS,iSCSI 或特定于云提供程序的存储系统。
**PersistentVolumeClaim(PVC)**是由用户进行存储的请求。它类似于pod。Pod 消耗节点资源,PVC 消耗PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以一次读/写或多次只读)。
虽然PersistentVolumeClaims 允许用户使用抽象存储资源,但是PersistentVolumes 对于不同的问题,用户通常需要具有不同属性(例如性能)。群集管理员需要能够提供各种PersistentVolumes 不同的方式,而不仅仅是大小和访问模式,而不会让用户了解这些卷的实现方式。对于这些需求,有StorageClass 资源。
StorageClass 为管理员提供了一种描述他们提供的存储的“类”的方法。不同的类可能映射到服务质量级别,或备份策略,或者由群集管理员确定的任意策略。Kubernetes 本身对于什么类别代表是不言而喻的。这个概念有时在其他存储系统中称为“配置文件”。PVC 和PV 是一一对应的。
PV 是群集中的资源。PVC 是对这些资源的请求,并且还充当对资源的检查。PV 和PVC 之间的相互作用遵循以下生命周期:
Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling
GCEPersistentDisk
AWSElasticBlockStore
AzureFile
AzureDisk
FC (Fibre Channel)
Flexvolume
Flocker
NFS
iSCSI
RBD (Ceph Block Device)
CephFS
Cinder (OpenStack block storage)
Glusterfs
VsphereVolume
Quobyte Volumes
HostPath (Single node testing only – local storage is not supported in any
way and WILL NOT WORK in a multi-node cluster)
Portworx Volumes
ScaleIO Volumes
StorageOS
(1)第一步:编写yaml 文件,并创建pv
创建5 个pv,存储大小各不相同,是否可读也不相同
apiVersion: v1
kind: PersistentVolume
metadata: name: pv001 labels:
name: pv001 spec:
nfs:
path: /data/volumes/v1
server: nfs
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity: storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata: name: pv002 labels:
name: pv002 spec:
nfs:
path: /data/volumes/v2
server: nfs
accessModes: ["ReadWriteOnce"] capacity:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume metadata:
name: pv003 labels:
name: pv003 spec:
nfs:
path: /data/volumes/v3 server: nfs
accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity:
storage: 20Gi
---
apiVersion: v1
kind: PersistentVolume metadata:
name: pv004 labels:
name: pv004 spec:
nfs:
path: /data/volumes/v4 server: nfs
accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
labels: name: pv005
spec:
nfs:
path: /data/volumes/v5
server: nfs
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 15Gi
(2)第二步:执行创建命令
kubectl apply -f pv-damo.yaml
(3)第三步:查询验证
6、演示:创建PVC,绑定PV
(1)第一步:编写yaml 文件,并创建pvc
创建一个pvc,需要6G 存储;所以不会匹配pv001、pv002、pv003
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 6Gi
---
apiVersion: v1
kind: Pod
metadata:
name: vol-pvc
namespace: default
spec:
volumes:
- name: html
persistentVolumeClaim:
claimName: mypvc
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
(2)第二步:执行命令创建
kubectl apply -f vol-pvc-demo.yaml
(3)第三步:查询验证
Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec 中。Secret 可以以Volume 或者环境变量的方式使用
• Service Account :用来访问Kubernetes API,由Kubernetes 自动创建,并且会自动挂载到Pod 的 /run/secrets/kubernetes.io/serviceaccount
目录中
• Opaque : base64 编码格式的Secret,用来存储密码、密钥等
• kubernetes.io/dockerconfigjson :用来存储私有docker registry 的认证信息
Service Account 用来访问Kubernetes API,甶Kubernetes 自动创建,并且会自动挂载到 Pod的/run/secrets/kubernetes.io/serviceaccount
目录中
$ kubectl run nginx --image nginx
deployment "nginx" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-3137573019-md1u2 1/1 Running 0 13s
$ kubectl exec nginx-3137573019-md1u2 #进入到pod里面
ls /run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token
(1)创建说明:Opaque 类型的数据是一个map 类型,要求value 是base64 编码格式
$ echo -n "admin" | base64
YWRtaW4=
$ echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm:
(2)secrets.yml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
(3)使用方式
将Secret 挂载到Volume 中
apiVersion: v1
kind: Pod
metadata:
labels:
name: seret-test
name: seret-test
spec:
volumes:
- name: secrets
secret:
secretName: mysecret
containers:
-image: hub.atguigu.com/library/myapp:v1
name: db
volumeMounts:
- name: secrets
mountPath:"
readOnly: true
将Secret 导出到环境变量中
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: pod-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: pod-deployment
spec:
containers:
- name: pod-1
image: hub.atguigu.com/library/myapp:v1
ports:
-containerPort: 80
env:
-name: TEST_USER
valueFrom:
secretKeyRef:
name: mysecret
key: username
使用Kuberctl 创建docker registry 认证的secret
$ kubectl create secret docker-registry myregistrykey --dockerserver= DOCKER_REGISTRY_SERVER -- docker-username=DOCKER_USER --dockerpassword= DOCKER_PASSWORD --docker-email=DOCKER_EMAIL secret "myregistrykey"
created.
在创建Pod 的时候,通过imagePullSecrets 来引用刚创建的’myregistrykey
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: foo
image: roc/awangyang:v1
imagePullSecrets:
-name: myregistrykey
ConfigMap 功能在Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON 二进制大对象