第一部分 K8S基本概念
1. K8S概述和特性
2. K8S架构组件
Master (主控节点)和 node (工作节点)
master 组件
apiserver ---> 集群统一入口,以 restfull 方式,交给 etcd 存储
scheduler ---> 节点调度,选择node节点应用部署
controller-manager ---> 处理集群中常规后台任务,一个资源对应一个控制器
node组件
kubelet ---> master 派到 node 节点代理,管理本机容器
kube-proxy ---> 提供网络代理,负载均衡等操作
3. K8S核心概念
- Pod
- controller
- Service
4. 集群 YML 文件详解
4.1 YAML 基本语法
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
低版本缩进时不允许使用 Tab 键,只允许使用空格
使用#标识注释,从这个字符一直到行尾,都会被解释器忽略
4.2 支持的数据结构
对象; 键值对集合 -----( 映射/哈希/字典)
Copy name : Tom
age : 18 === hash : { name : Tom , age : 19 }
数组 ; 序列 ?列表
Copy People
- Tom
- Jack === People : [ Tom , Jack ]
纯量( scalars ), 不可分的值
Copy number : 12.30 浮点数
isSet : true 布尔值
parent : ~ null 用 ~ 表示
iso8601 : 2001-12-14t21:59:43.10-05:00 时间采用 iso8601 格式
date : 1976-07-31 日期
字符串可以写成多行,第二行需有一个空格缩减
4.3 资源清单表述方法
4.3-1 YAML 必须存在的属性
api版本,目前v1, 可用kubect api-version查看
4.3-2 YAML Spec 主要对象
spec.containers[].imagePullPolicy
默认 Always; 定义镜像拉取策略,有Always(总是)、Never(使用本地)、IfNotPresent(如果本地没有就拉取);
spec.containers[].command[]
指定容器启动命令,可指定多个,不指定默认使用容器打包的启动命令
spec.containers[].workingDir
spec.containers[].volumeMounts[]
spec.containers[].valumeMounts[].name
spec.containers[].valumeMounts[].mountPath
spec.containers[].valumeMounts[].readOnly
设置存储卷路径的读写模式,true或者false,默认为读写模式
spec.containers[].ports[]
spec.containers[].ports[].name
spec.containers[].ports[].containerPort
spec.containers[].ports.hostPort
指定容器所在主机需要监听的端口号,默认和 containerPort相同,如果设置了hostport,同一台主机无法启动相同副本,会冲突
spec.containers[].ports[].protocol
spec.containers[].env[].name
spec.containers[].env[].value
spec.containers[].resources
spec.containers[].resources.limits
spec.containers[].resources.limits.cpu
指定CPU限制,单位 core 数,将用于 --cpu-shares 参数
spec.containers[].resources.limits.memory
spec.containers[].resources.requests
spec.containers[].resources.requests.cpu
CPU请求,单位 core 数,容器启动时初始化可用数量
spec.containers[].resources.requests.memory
内存请求,单位MIB,GIB,容器启动时初始化可用数量
4.3-3 YAML 额外的参数
定义Pod重启策略,可以选择值为Always、OnFailure,默认为Always. Always: Pod一旦终止运行,将重启它。 2.OnFilure ,只有Pod以非零退出码终止时,重启,否则,不重启。 3. Never: Pod终止后,将退出码报告给Mater,不会重启改Pod
定义Node的Label过滤标签,以key:value格式指定
定义pull镜像是使用secrets名称,以name:secretKey格式指定
定义是否使用主机忘了默认,默认值false,设置true表示使用宿主机忘了,不适用docker网桥,同时设置true将无法在一台宿主机上启动第二个副本
4.3-4 举例说明
Copy # 创建一个命名空间 namespace, 创建一个Pod
apiVersion : v1
kind : Namespace
metadata :
name : test
---
apiVersion : v1
kind : Pod
metadata :
name : pod1
spec :
containers :
- name : ningx-containers
image : nginx:latest
Copy kubectl get namespaces # 查看命名空间
kubectl get pods # 查看pod
kubectl describe pods/pod1 # 查看指定pod
5. kubectl 命令集合
5.1 基础命令解释
通过文件名、标准输入、资源名称或标签选择器来删除资源
5.2 部署和集群管理命令解释
扩容或缩容Pod数量,Deployment、ReplicaSet、RC或Job
显示资源(CPU/Memory/Storage)使用
5.3 故障和调试命令解释
在一个Pod中打印一个容器日志。如果Pod只有一个容器,容器名称是可选的
5.4 其他命令解释
修改kubeconfig文件(用户访问API,比如配置认证信息)
5.5 如何跨省编写 yaml 文件
1、第一种 使用 kubectl create 命令生成 yaml 文件
Copy kubectl create deploy web --image=nginx -o yaml --dry-run > my.yaml
2、第二中 使用 **kubectl get ** 命令导出yaml文件 ; <适用于已有部署集>
Copy kubectl get deploy < 部署集名 字 > -o yaml --export > my.yaml
Copy # create 语法: kubectl create -f FILANEM [flags]
- kubectl create -f xx.yaml -f xx.yaml # 创建资源 或 多个资源
- kubectl create -f ./dir # 使用目录下所有 yaml 文件创建资源
- kubectl create -f http://baidu.com/xxx.yaml# 使用 url 创建资源
- kubectl create namespace myspace # 创建名字为 myspace 的命名空间
- kubectl delete namespace myspace # 删除名字为 myspace 的命名空间
# expose 将副本控制器、服务或 pod 作为新的 Kubernetes 服务暴露 ,语法:
kubectl expose (-f FILENAME | TYPE NAME | TYPE/NAME ) [–port = port] [–protocol = TCP | UDP] [–target-port = number-or-name] [–name = name] [–external-ip = external-ip-of-service] [–type = type] [flags]
- kubect expose rc nginx --port=80 --tarport=8000 # 为副本控制器(rc)的nginx创建service,并通过service的80端口转发到容器的8000端口上
- kubect expose -f xxx.yml # 由xxx.yml中指定的type和name表示的RC创建Service,并通过service的80端口转发到容器的8000端口
# run
kubectl run nginx --image=nginx # 启动nginx实例
kubectl run nginx --image=nginx --port=80 # 启动nginx实例,并暴露容器80端口
kubectl run nginx --image=nginx --replicas=5 # 启动nginx实例,设置副本数5
kubectl run nginx --image=nginx --env= "DNS_DOMAIN=cluster" --env= "POD_NAMESPACE=default" # 启动nginx实例,并设置变量
Copy kubectl get namespaces # 查看所有命名空间及状态, 查看某一个,后面加上命名空间名字
kubectl describe namespaces < 命名空 间 > # 查看命名空间信息
kubectl create namespace < 命名空 间 > # 创建命名空间
kubectl create deploy < 部署集名 字 > -image=nginx --namespace= < 名称空间名字 > # 在指定命名空间上部署应用
kubectl get deploy -n < 命名空 间 > # 查看命名空间下的部署集
kubectl delete deploy < 部署集名 字 > # 直接删除pod会触发部署集,重新创建pod,所以直接删除部署集
kubectl delete namespace < 命名空 间 > # 此操作会删除该命名空间下的所有资源
kubectl describe pods < pod名 字 > -n < 命名空 间 > # 查看某个命名空间下某个pod的详细信息
kubectl logs < po d > -n < 命名空 间 > # 查看pod日志
第二部分 搭建K8S集群
方法一:使用 kubeadm 方式搭建k8s集群
1. 三台 Centos7.x 服务器
2. 所有节点初始化操作
Copy # 关闭防火墙
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 < hostnam e >
# 只在master添加hosts
cat >> /etc/hosts << EOF
192.168.44.134 k8s-master
192.168.44.135 k8s-node01
192.168.44.136 k8s-node02
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
3. 所有节点安装程序包
所有节点:docker 、kubelet 、kubeam 、kubctl
3.1 安装 Docker
Copy yum install wget -y
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
# 显示: Docker version 18.06.1-ce, build e68fc7a
# 由于国内服务器,拉取国外镜像过慢,配置镜像加速
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
3.2 添加阿里云YUM软件源
Copy 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.3 安装kubeadm,kubelet和kubectl
Copy # 由于版本更新频繁,这里指定版本号部署:
yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
systemctl enable kubelet
4. Master 集群初始化
kubeadm init命令
Copy # Master(192.168.1.134) 上执行, 其他ip端只要不冲突即可
kubeadm init \
--apiserver-advertise-address=192.168.1.134 \
--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
# 初始化成功后,依据提示执行
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
5. Node 节点添加到当前集群中
Copy kubeadm join 192.168 . 1 . 134 : 6443 --token pvx7z8 . ubvh64gsfv5l5tw0 \
--discovery - token - ca - cert - hash sha256 : c65c8e0f8e4f897bfdbe9160f69e380942e4d6e38e6690e435b5d2a4bd0d3294
6.所有节点配置网络插件
Copy # wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-amd64-2pc95 1/1 Running 0 72s
7. 测试kubernetes集群
Copy # 在Master节点,在Kubernetes集群中创建一个pod,验证是否正常运行:
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc
访问地址:http://NodeIP:Port
方法二:二进制方式
1. 三台 Centos7.x 服务器
2. 所有节点初始化操作
Copy # 关闭防火墙
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 < hostnam e >
# 只在master添加hosts
cat >> /etc/hosts << EOF
192.168.1.134 k8s-master
192.168.1.135 k8s-node01
192.168.1.136 k8s-node02
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
3. 准备 cfssl 证书生成工具
Copy 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
3.1 创建工作目录
Copy mkdir -p ~/TLS/{etcd,k8s}
cd TLS/etcd
3.2 创建生成 Etcd Ca 证书配置
Copy # 自签证书
cat << EOF | tee ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"www": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat << EOF | tee ca-csr.json
{
"CN": "etcd CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
3.3 创建 ETCD Server申请文件
Copy cat << EOF | tee server-csr.json
{
"CN": "etcd",
"hosts": [
"192.168.1.134",
"192.168.1.135",
"192.168.1.136"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
# 注:上述文件 hosts 字段中 IP 为所有 etcd 节点的集群内部通信 IP,一个都不能少!为了 方便后期扩容可以多写几个预留的 IP。
3.4 生成 Etcd HTTPS证书
Copy # 生成自签Etcd CA 证书, 并使用自签 CA 签发 ETCD 证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server
ls ca*pem && ls server*pem
3.5 创建生成 kube-apiserver 配置
Copy cd ~/TLS/k8s/
# 自签证书颁发机构(CA)
cat << EOF | tee ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat << EOF | tee ca-csr.json
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
3.6 创建 kube-apiserver 证书申请文件
Copy cat << EOF | tee server-csr.json
{
"CN": "kubernetes",
"hosts": [
"10.0.0.1",
"127.0.0.1",
"192.168.1.134",
"192.168.1.135",
"192.168.1.136",
"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
3.7 生成 kube-apiserver HTTPS 证书
Copy # 生成CA证书, 然后使用自签 CA 签发 kube-apiserver HTTPS 证书
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server
ls ca*pem && ls server*pem
4. 部署Etcd集群
4.1 下载安装包
Copy cd ~/TLS/etcd
wget https://github.com/etcd-io/etcd/releases/download/v3.4.9/etcd-v3.4.9-linux-amd64.tar.gz
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/
4.2 拷贝刚才生成的证书
Copy cp ~/TLS/etcd/ca*pem ~/TLS/etcd/server*pem /opt/etcd/ssl/
4.3 创建 etcd配置文件
Copy cat << EOF | tee /opt/etcd/cfg/etcd.conf
#[Member]
ETCD_NAME="etcd-1"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://192.168.1.134:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.134:2379"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.134:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.134:2379"
ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.1.134:2380,etcd-2=https://192.168.1.135:2380,etcd-3=https://192.168.1.136:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
4.4 使用Systemd管理 etcd
Copy cat << EOF | tee /usr/lib/systemd/system/etcd.service
[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.5 拷贝文件到 Node 节点
Copy # 注意复制过去后,修改下 etcd.conf 中IP地址,为节点的IP
scp -r /opt/etcd/ root@192.168.1.135:/opt/
scp -r /opt/etcd/ root@192.168.1.136:/opt/
scp /usr/lib/systemd/system/etcd.service root@192.168.1.135:/usr/lib/systemd/system/
scp /usr/lib/systemd/system/etcd.service root@192.168.1.136:/usr/lib/systemd/system/
4.6 启动 etcd
Copy # 启动ETCD集群同时启动二个节点,单节点是无法正常启动的。
systemctl daemon-reload && systemctl start etcd && systemctl enable etcd
4.7 检查服务是否正常
Copy 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.1.134:2379,https://192.168.1.135:2379,https://192.168.1.136:2379" endpoint health
https://192.168.1.134:2379 is healthy: successfully committed proposal: took = 9.978053ms
https://192.168.1.136:2379 is healthy: successfully committed proposal: took = 13.282176ms
https://192.168.1.135:2379 is healthy: successfully committed proposal: took = 12.787146ms
# 显示结果如上。如果不正常,查看日志: /var/log/message 或者 journalctl -u etcd
5. 安装 Docker
所有节点上
5.1 下载源码包
Copy wget https://download.docker.com/linux/static/stable/x86_64/docker-19.03.9.tgz
tar zxvf docker-19.03.9.tgz
mv docker/* /usr/bin
5.2 Systemd 管理 docker
Copy cat << EOF | tee /usr/lib/systemd/system/docker.service
[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
5.3 加速镜像
Copy mkdir /etc/docker
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
5.4 开机自启
Copy systemctl daemon-reload && systemctl start docker && systemctl enable docker
6. 部署 Master Node
下载地址: https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md
这里使用版本: v1.18.3 , 下载 server 包,里面啥都有
安装 master 必须组件
6.1 下载二进制包
Copy wget https://dl.k8s.io/v1.18.13/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/
Copy # 把刚才生成的证书拷贝到配置文件中的路径
cp ~/TLS/k8s/ca*pem ~/TLS/k8s/server*pem /opt/kubernetes/ssl/
6.2 启用 TLS Bootstrapping 机制
Copy # token 生成 ====> head -c 16 /dev/urandom | od -An -t x | tr -d ' '
# 格式:token,用户名,UID,用户组
cat > /opt/kubernetes/cfg/token.csv << EOF
c47ffb939f5ca36231d9e3121a252940,kubelet-bootstrap,10001,"system:node-bootstrapper"
EOF
6.3 部署 kube-apiserver
Copy # 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.1.134:2379,https://192.168.1.135:2379,https://192.168.1.136:2379 \\
--bind-address=192.168.1.134 \\
--secure-port=6443 \\
--advertise-address=192.168.1.134 \\
--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
Copy # systemd 管理
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
Copy # 授权 kubelet-bootstrap 用户允许请求证书
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap
参数详解: –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:审计日志
6.4 部署kube-controller-manager
Copy 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
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
–master:通过本地非安全本地端口8080连接apiserver。 –leader-elect:当该组件启动多个时,自动选举(HA) –cluster-signing-cert-file/–cluster-signing-key-file:自动为kubelet颁发证书的CA,与apiserver保持一致
6.5 部署kube-scheduler
Copy 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
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
#### 查看集群状态
[root@k8s-master ~ ]# kubectl get cs
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-2 Healthy { "health" : "true" }
etcd-0 Healthy { "health" : "true" }
etcd-1 Healthy { "health" : "true" }
7. 部署Worker Node
下面还是在 Master 上操作,即同时作为 Worker Node
7.1 创建工作目录并拷贝二进制文件
Copy mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
# 之前下载的 k8s server 包
cd kubernetes/server/bin
cp kubelet kube-proxy /opt/kubernetes/bin
7.2 部署 kubelet
Copy # 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
# 2. 设置配置参数文件
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
# 3. 生成bootstrap.kubeconfig文件
KUBE_APISERVER = "https://192.168.1.134:6443"
TOKEN = "c47ffb939f5ca36231d9e3121a252940"
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
# 4. 拷贝到配置文件路径
cp bootstrap.kubeconfig /opt/kubernetes/cfg
Copy 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
Copy # 查看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
NAME STATUS ROLES AGE VERSION
k8s-master NotReady < non e > 7s v1.18.3 # 注:由于网络插件还没有部署,节点会没有准备就绪 NotReady
7.3 部署kube-proxy
Copy # 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
# 2. 配置文件参数
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
# 3. 创建证书请求文件
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
# 4. 生成证书
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
# 5. 生成kube-proxy.kubeconfig文件
KUBE_APISERVER = "https://192.168.1.134: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
# 6. 拷贝到配置文件指定路径
cp kube-proxy.kubeconfig /opt/kubernetes/cfg/
Copy 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
7.4 部署CNI网络
部署
Copy # 必须是 /opt/cni/bin 路径,不然 node 不是 Ready , https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-amd64-v0.8.6.tgz
mkdir /opt/cni/bin -p
tar zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin
# flannel 地址:https://github.com/flannel-io/flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 查看是否在安装
kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-amd64-2pc95 1/1 Running 0 72s
# 查看是否已经准备就绪
kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready < non e > 41m v1.18.3
授权 apiserver 访问 kubelet
Copy 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
7.5 增加Worker Node
Copy # 1. 在 master 节点将 Worker Node 涉及文件拷贝到新节点
scp -r /opt/kubernetes root@192.168.1.135:/opt/
scp -r /opt/kubernetes root@192.168.1.136:/opt/
scp -r /usr/lib/systemd/system/{kubelet,kube-proxy}.service root@192.168.1.135:/usr/lib/systemd/system
scp -r /usr/lib/systemd/system/{kubelet,kube-proxy}.service root@192.168.1.136:/usr/lib/systemd/system
scp -r /opt/cni/ root@192.168.1.135:/opt/
scp -r /opt/cni/ root@192.168.1.136:/opt/
scp /opt/kubernetes/ssl/ca.pem root@192.168.1.135:/opt/kubernetes/ssl
scp /opt/kubernetes/ssl/ca.pem root@192.168.1.136:/opt/kubernetes/ssl
# 2. 在新节点上删除kubelet证书和kubeconfig文件; 注:这几个文件是证书申请审批后自动生成的,每个Node不同,必须删除重新生成。
rm -f /opt/kubernetes/cfg/kubelet.kubeconfig
rm -f /opt/kubernetes/ssl/kubelet*
# 3. 在新节点上修改主机名; kebelet、 kube-proxy
vi /opt/kubernetes/cfg/kubelet.conf
--hostname-override = k8s-node01
vi /opt/kubernetes/cfg/kube-proxy-config.yml
hostnameOverride: k8s-node01
# 4. 在新节点上启动并设置开机启动
systemctl daemon-reload
systemctl start kubelet kube-proxy
systemctl enable kubelet kube-proxy
systemctl status kubelet kube-proxy
# 5. 回到 Master 上批准新Node kubelet证书申请
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-4zTjsaVSrhuyhIGqsefxzVoZDCNKei-aE2jyTP81Uro
# 6. 查看Node状态
kubectl get node
第三部分 K8S核心技术
1. Pod
1.1 Pod 基本概念
1.2 Pod 实现机制
共享网络: 通过Pause容器,把其他业务容器加入到Pansu容器里,让所有业务容器在同一个命名空间中,实现网络共享
共享存储: 引入数据卷 Volumn,使用数据卷进行持久化存储
若Pod节点发生故障,那么该Pod会调度到其他节点,是一个全新的Pod,跟之前的pod无关联
所有Pod都在同一共享网络地址空间中,每个Pod可以通过其他Pod的IP进行访问
1.3 Pod 生命周期和重启策略
API Server已经创建该Pod,但Pod中的一个或多个容器还没创建,包括镜像下载过程
Pod内错有容器已创建,且至少一个容器处于运行状态、正在启动或正在重启
当容器终止运行且退出码不为0,由kubelet自动重启该容器
不论容器运行状态如何, kublete都不会重启该容器
Pod包含的容器数
Pod当前的状态
发生事件
Pod的结果状态
1.4 Pod 资源配置
Copy apiVersion : v1
kind : Pod
metadata :
name : pod-demo
labels :
app : myapp
spec :
containers :
- name : myapp
image : nginx
resources :
requests :
cpu : "200m"
memory : "128Mi"
limits :
cpu : "500m"
memory : "512Mi"
# 上述代码表明 Nginx 容器申请最少 0.2 个 CPU 以及 128MiB 内存,在运行过程中容器所能使 用的资源配额为 0.5 个 CPU 以及 512MiB 内存。
1.5 Pod 健康检查
livenessProbe (存活检查)
如果检查失败,将杀死容器,根据Pod的 restartPolicy 来操作
readlinessProbe (就绪检查)
如果检查失败, Kubernetes会把Pod从 service endpoint中剔除
发送HTTP请求,返回200·400范围状态码为成功
1.6 Pod 创建流程
- 1、 kubect 向 Apiserver 发送创建Pod请求 - 2、Api server 收到请求,生成 YAML 文件,并把YAML信息写入 Etcd 中 - 3、 Scheduler 调度器通过Apiserver 读取 Etcd 信息进行判断,如果是NUll,使用调度算法,分配到资源利用少的节点上,并把更新信息写入 Etcd内, - 4、Node 节点上 的 kubelet 会不停的请求 apiserver,读取Etcd数据,如果编号和自己的相同,则调用 dcokerApi,创建容器
1.7 Pod 调度(节点亲和)
- 硬亲和性: 约束条件必须满足 - 软亲和性: 尝试满足,不保证
支持常用操作符: In NotIn Exists Gt Lt DoesNotExists
影响调度的属性
Pod 资源限制对Pod调用产生影响 ( 设置资源限制过大,会找不到足够资源的node节点)
节点选择器标签影响 Pod 调度 (只可调用到指定标签的节点)
1.8 Pod 调度(节点污点)
污点值 <常用于master节点> - Noschedule 一定不被调度 - PreferNoSchedule 尽量不被调度 - NoExecute 不会调度,并且驱逐已有的 Pod
Copy # 查看污点
kubectl describe node < 节点名 字 > | grep -i taint
# 为节点添加污点
kubectl taint node < 节点名 称 > key=value: < 污点 值 >
# 删除污点,注意后面要加 -
kubectl taint node < 节点名 称 > key=value: < 污点 值 > -
污点容忍
比如某个节点节点被标记为了污点节点,要想 pod 能够调度到 master 节点去,这个该怎么办?```
Copy tolerations :
- key : "key"
operator : "Exists"
value : 'Equal'
effect : "NoSchedule"
# 或者
tolerations :
- key : "key"
operator : "Exists"
effect : "NoSchedule"
# 如果 operator 的值是 Exists,则 value 属性可省略
# 如果 operator 的值是 Equal,则表示其 key 与 value 之间的关系是 equal(等于)
# 如果不指定 operator 属性,则默认值为 Equal
2. Controller
2.1 什么是 Controller?
在集群上管理和运行容器的对象,俗称控制器
2.2 Pod 与 Controller 关系?
Pod 是通过 Controller 实现应用的运维,比如伸缩、滚动升级等等
2.3 Deployment 控制器应用场景
部署,滚动升级等功能
------- 主要应用场景: web服务、微服务
2.4 Yaml 文件字段说明
Copy # 使用 deployment 部署应用(上下选择标签要相同)
···
spec :
replicas : 1
selector :
matchLabels :
app : web
template :
metadata :
labels :
app : web
2.5 Deployment 控制器部署应用
Copy # 1. 导出 Yaml 文件 <主要是为了后面重新生成>
kubectl create deploy web --image=nginx --dry-run=client -o yaml > web.yaml
# 2. 部署应用
kubectl apply -f web.yaml
# 3. 对外发布 (暴露对外端口号,这种方法,一个端口只能用于这一个应用)
kubectl expose deploy web --port=80 --target-port=80 --type=NodePort --name=web1 -o yaml > web1.yaml
kubectl apply -f web1.yaml
kubectl get svc ---- > web1 NodePort 10.0.0.202 < non e > 80:31281/TCP 2m56s
# 测试端口访问
curl localhost:31281
2.6 应用升级回滚和弹性伸缩
Copy # 应用升级版本
kubectl set image deploy web nginx=nginx:1.15
# 查看升级的状态
kubectl rollout status deploy web
# 查看升级的版本
kubectl rollout history deploy web
# 新版本不好用,再切回来老版本;回滚
kubectl rollout undo deploy web
# 回滚到指定的版本
kubectl rollout undo deploy web --to-revision=2
# 手动弹性伸缩
kubectl scale deploy web --replicas=5
3. Service
服务发现
3.1 Service 存在意义
3.2 Service 和 Pod 关系
- Pod 类似架构中的 后端服务器, Service 相当于架构中的虚拟 VIP,通过Service实现负载均衡
- Pod 与 Service 根据 Label 和 selector 标签选择器建立关联
3.3 Servier 类型
3、LoadBalancor: 对外访问应用使用,公有云
4. 无状态和有状态
4-1 无状态
4-2 有状态
会让每个Pod独立,保持 Pod 启动顺序和唯一性
4-3 部署有状态应用
无头Service
ClusterIP: none # 通过YAML文件设置 ClusterIP 为 None
SatefulSet 部署有状态应用
kind: StatefulSet # 通过YAML文件设置 kind 为 StatefulSet
- 能保证每个 Pod 名称唯一性
注意: deployment 和 SatefulSet 区别:<唯一标识不同>
deployment : 根据主机名 + 安装一定规则生成域名 SatefulSet: 根据主机名称.service名称.名称空间.svc.cluster.local
3.4-4 DaemonSet 守护进程
在每个node上运行一个pod, 新加入的 node 也同样运行这个pod
5 计划任务
5.1 一次性任务
Copy apiVersion : batch/v1
kind : Job
metadata :
name : myjob
spec :
# 同时启动两个任务
#parallelism: 2
template :
metadata :
name : myjb
spec :
containers :
- name : hello
image : busybox
command : [ "echo" , "hello k8s job" ]
restartPolicy : Never
# 常用命令
kubectl get jobs
kubectl delete jobs xxx
5.2 定时任务
Copy apiVersion : batch/v1beta1
kind : CronJob
metadata :
name : mycronjob
spec :
schedule : "*/1 * * * *"
jobTemplate :
spec :
template :
metadata :
name : mycronjob
spec :
containers :
- name : hello
image : busybox
command : [ "echo" , "hello k8s job" ]
restartPolicy : OnFailure
# 常用命令
kubectl get cronjob
kubectl delete cronjob xxx
6. Secret
6.1 Secret存在意义
Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露 到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用
作用: 加密数据存在 etcd 里面, 让 Pod 容器以挂载 Volume 方式镜像访问
场景: 凭证
6.2 Secret 有三种类型
Service Account :用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中
Opaque : base64 编码格式的 Secret,用来存储密码、密钥等
kubernetes.io/dockerconfigjson :用来存储私有 docker registry 的认证信息
6.2-1 Service Account
Copy kubectl run nginx --image nginx
kubectl exec nginx ls /var/run/secrets/kubernetes.io/serviceaccount
> ca.crt namespace token
6.2-2 Opaque Secret
1. 编写一个 secret 对象
Copy echo -n "admin" | base64 --- > YWRtaW4=
echo -n "1f2d1e2e67df" | base64 --- > MWYyZDFlMmU2N2Rm:
# cat secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type : Opaque
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
kubectl apply -f secrets.yaml
kubectl get secret
> mysecret Opaque 2 32s
2. 将 Secret 挂载到Volume中
Copy # cat pod1.yml
apiVersion : v1
kind : Pod
metadata :
name : mysecret
spec :
containers :
- name : demo
image : myapp:v1
volumeMounts :
- name : secrets
mountPath : "/secret"
readOnly : true
volumes :
- name : secrets
secret :
secretName : mysecret
#items: 向指定路径映射 secret 密钥
#- key: username
# path: my-group/my-username #相对路径
kubectl apply -f pod1.yml
kubectl exec mysecret -- ls /secret
3. 将 Secret 设置为环境变量
缺点: 环境变量读取 Secret 很方便,但无法支撑Secret动态更新。
Copy # cat pod2.yml
apiVersion : v1
kind : Pod
metadata :
name : secret-env
spec :
containers :
- name : nginx
image : myapp:v1
env :
- name : SECRET_USERNAME
valueFrom :
secretKeyRef :
name : mysecret
key : username
- name : SECRET_PASSWORD
valueFrom :
secretKeyRef :
name : mysecret
key : password
kubectl apply -f pods.yml
kubectl exec secret-env -- env
> SECRET_USERNAME=admin
> SECRET_PASSWORD=1f2d1e2e67df
6.2-3 dockerconfigjson
kubernetes.io/dockerconfigjson 用于存储 docker registry 的认证信息.
Copy # 使用 Kuberctl 创建 docker registry 认证的 secret
kubectl create secret docker-registry myregistrykey --docker- server=DOCKER_REGISTRY_SERVER -- docker-username=DOCKER_USER --docker- password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
> secret "myregistrykey" created.
# cat pod3.yml 在创建 Pod 的时候,通过 imagePullSecrets 来引用刚创建的'myregistrykey
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mario
image: reg.westos.org/westos/mario
imagePullSecrets:
- name: myregistrykey ##没有则无法访问私有仓库
6.3 ConfigMap
作用: 存储不加密数据到 etcd, 让Pod以变量或者Volume挂载到容器中 场景: 配置文件
6.3-1 Pod 使用 ConfigMap 方式?
使用Volume将ConfigMap作为文件或目录挂载
注意: - ConfigMap必须在Pod使用它之前创建 - 使用envFrom时,将会自动忽略无效的键 - Pod只能使用同一个命名空间的ConfigMap
6.3-2 创建ConfigMap两种方式
方式(1):命令行方式
Copy kubectl create configmap nginxconfig --from-file /server/yaml/nginx/nginx.conf #通过命令直接创建
kubectl get configmap nginxconfig -o yaml #查看文件
方式(2):YMAL文件方式
Copy cat nginx-configmap.yaml
#-----------------------------创建命名空间----------------------------
apiVersion : v1
kind : Namespace
metadata :
name : mt-math #创建的命名空间名称为mt-math
---
#-----------------------------创建configmap文件-----------------------
#创建configmap有多种方式,可以通过命令如:
#kubectl create configmap nginxconfig --from-file /server/yaml/nginx/nginx.conf
#查看创建的yaml文件内容:kubectl get configmap nginxconfig -o yaml
#这里采用标准的yaml文件格式进行创建:更新时采用:kubectl replace -f nginx-configmap.yaml
apiVersion : v1
kind : ConfigMap
metadata :
name : nginxconfig
namespace : mt-math
data :
nginx.conf : |
#########wyl530
user nginx;
worker_processes auto;
error_log /etc/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
server_tokens off;
access_log /usr/share/nginx/html/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
创建pod yaml文件
Copy cat deployment.yaml
#----------------------------创建pv---------------------------------
apiVersion : v1
kind : PersistentVolume
metadata :
name : pv-nfs-pv01 #创建的pv名称可创建多个.
namespace : mt-math #属于的命名空间
labels :
pv : pv-nfs-01 #定义pv标签,后续通过pvc绑定特定的pv标签。通常如果不写标签则默认通过访问方式和storage大小进行批量绑定。(重要)
spec :
capacity :
storage : 1Gi #创建的pv-nfs-pv01大小为1G
accessModes :
- ReadWriteMany
nfs : #创建的pv数据来源
path : /NFS/pv01 #数据源目录
server : 192.168.0.14 #数据源ip
#--------------------------------创建pvc--------------------------------
---
kind : PersistentVolumeClaim
apiVersion : v1
metadata :
name : nfs-data-pvc #创建的pvc名称
namespace : mt-math #属于的命名空间
spec :
accessModes :
- ReadWriteMany
resources :
requests :
storage : 1Gi #请求大小为1G
selector : #定义标签选择器,此时k8s会根据标签,storage,访问方式 进行匹配。三者同时满足才会绑定。如果不定义,则系统会根据storage的大小和访问方式进行匹配绑定.
matchLabels :
pv : pv-nfs-01 #定义请求标签为pv-nfs-pv01的pv且大小为1G
#--------------------------------创建pod------------------------------------
---
apiVersion : extensions/v1beta1 #接口版本
kind : Deployment #接口类型
metadata : #基础标签名称信息
name : wyl-nginx #创建的pod名称
namespace : mt-math #创建的pod属于mt-math命名空间
spec : #详细参数设置
replicas : 3 #副本数量
selector : #标签选择器
matchLabels :
app : wyl-nginx #正对标签为wyl-nginx的pod进行副本的创建
strategy :
rollingUpdate : #由于replicas为3,则整个升级,pod个数在2-4个之间
maxSurge : 1 #滚动升级时会先启动1个pod
maxUnavailable : 1 #滚动升级时允许的最大Unavailable的pod个数
template : #模板
metadata :
labels :
app : wyl-nginx #模板pod名称必填
spec : #定义容器模板信息,该模板可以包含多个容器
containers :
- name : nginx
image : nginx:latest
imagePullPolicy : IfNotPresent
ports :
- name : http
containerPort : 80
volumeMounts :
- name : nginx-nfs
mountPath : /usr/share/nginx/html
- name : nginx-pvc
mountPath : /var/log/nginx
subPath : nginx.conf
- name : nginx-etc #挂载数据节点名称
mountPath : /etc/nginx/nginx.conf #挂载此目录
subPath : nginx.conf
volumes : #设置挂载
- name : nginx-nfs #挂载的数据节点名称
nfs : #挂载的服务类型
server : 192.168.0.14 #服务Ip
path : /NFS/wwwroot #挂载数据目录
- name : nginx-pvc #挂载数据节点名称
persistentVolumeClaim : #服务类型
claimName : nfs-data-pvc #数据源名称
- name : nginx-etc #挂载数据节点名称
configMap :
name : nginxconfig #指定创建configMap的名称
items :
- key : nginx.conf #key为文件名称
path : nginx.conf #文件路径内容
---
#-----------------------创建server-------------------------------------------
kind : Service
apiVersion : v1
metadata :
name : wyl-nginx
namespace : mt-math #属于的命名空间
spec :
selector :
app : wyl-nginx #针对标签为wyl-nginx的标签进行负载
type : NodePort #正对Node节点进行端口暴露
ports :
- protocol : TCP #使用端口的协议
port : 3017 #供内网访问暴露的端口
targetPort : 80 #目标pod的端口
nodePort : 33333 #node节点暴露的端口
#简单说明-------------------------------------------------------------------
#1.创建了mt-math命名空间,删除命名空间默认删除该命名空间下的所有资源服务
#2.创建了pv,pv不属于任何命名空间
#3.创建了pvc,pvc属于mt-math命名空间
#4.创建了pod属于mt-math命名空间
#5.创建了server属于mt-math命名空间
#6.建议将pv单独写到一个文件中.否则在我们删除改命名空间下的所有服务后,利用该文件再次创建时会报pv已经创建.
#---------------------------------------------------------------------------
创建资源服务
Copy kubectl create -f /server/yaml/nginx/nginx-configmap.yaml
kubectl create -f /server/yaml/nginx/deployment.yaml
kubectl exec -it wyl-nginx-d6f68d775-l4rkb --namespace=mt-math -- cat /etc/nginx/nginx.conf |head -1
7. 集群安全机制
7.1 概述
RBAC 实现机制:基于角色的访问控制
大白话: 白名单机制,想让他具备什么权限,就先创建某个角色Role,然后定制rules,再将某个用户user与role绑定,bind得到这种绑定关系为RoleBind
- Role 权限的集合 - ClusterRole 集群角色 - RoleBinding 角色绑定 - ClusterRoleBinding 集群角色绑定
8. helm
8.1 Helm 安装<包管理工具>
helm:一个命令行客户端工具,主要用于 Kubernetes 应用 chart 的创建、打包、发 布和管理。
Chart:应用描述,一系列用于描述 k8s 资源相关文件的集合。
Release:基于 Chart 的部署实体,一个 chart 被 Helm 运行后将会生成对应的一个 release;将在 k8s 中创建出真实运行的资源对象。
Copy # Helm 客户端下载地址:https://github.com/helm/helm/releases
wget https://get.helm.sh/helm-v3.2.1-linux-amd64.tar.gz
tar fx helm-v3.2.1-linux-amd64.tar.gz
mv linux-amd64/helm /usr/bin/
# 添加存储库
helm repo add stable http://mirror.azure.cn/kubernetes/charts
helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
helm repo update
# 查看配置的存储库
helm repo list
helm search repo stable
# 删除某个存储库,比如aliyun
helm repo remove aliyun
helm 配置国内 chart 仓库 微软仓库: http://mirror.azure.cn/kubernetes/charts 阿里云仓库: https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 官方仓库: https://hub.kubeapps.com/charts/incubator
下载一个release.可用子命令: all 、hooks、manifest、notes、values
将 chart 目录打包到 chart 存档文件中
添加,列出,移除,更新和索引chart仓库:可用子命令add, index, list, remove, update
根据关键字搜索chart。可用子命令: all, repo
查看chart想想信息,可用子命令:all,chart,readme,values
8.2 使用 chart 部署一个应用
Copy helm search repo weave
helm install ui stable/weave-scope
helm list
# 源码安装: 提示错误: Error: Kubernetes cluster unreachable
# export KUBERNETES_MASTER=http://127.0.0.1:8080 只需要指定一下apiserver的地址和端口号即可
# 修改 service Type: NodePort 即可访问 ui
9. Ingress
9.1 概述
Copy 在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes 目前 提供了以下几种方案:
- NodePort
- LoadBalancer
- Ingress
# 组成
ingress controller
将新加入的Ingress转化成Nginx的配置文件并使之生效
ingress服务
将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可
9.2 工作原理
Copy 1. ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化
2. 然后读取它,按照自定义的规则,规则里写明了哪个域名对应哪个service,生成一段nginx配置,
3. 再写到nginx-ingress-control的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中
4. 然后reload一下使配置生效。以此达到域名分配置和动态更新的问题。
9.3 部署Ingress 两种方式
下载部署文件
Copy # Github 地址: https://github.com/kubernetes/ingress-nginx
wget https://github.com/kubernetes/ingress-nginx/blob/nginx-0.30.0/deploy/static/mandatory.yaml
1.namespace.yaml
创建一个独立的命名空间 ingress-nginx
2.configmap.yaml
ConfigMap是存储通用的配置变量的,类似于配置文件,使用户可以将分布式系统中用于不同模块的环境变量统一到一个对象中管理;而它与配置文件的区别在于它是存在集群的“环境”中的,并且支持K8S集群中所有通用的操作调用方式。
从数据角度来看,ConfigMap的类型只是键值组,用于存储被Pod或者其他资源对象(如RC)访问的信息。这与secret的设计理念有异曲同工之妙,主要区别在于ConfigMap通常不用于存储敏感信息,而只存储简单的文本信息。
ConfigMap可以保存环境变量的属性,也可以保存配置文件。
创建pod时,对configmap进行绑定,pod内的应用可以直接引用ConfigMap的配置。相当于configmap为应用/运行环境封装配置。
pod使用ConfigMap,通常用于:设置环境变量的值、设置命令行参数、创建配置文件。
3.default-backend.yaml
如果外界访问的域名不存在的话,则默认转发到default-http-backend这个Service,其会直接返回404:
4.rbac.yaml
负责Ingress的RBAC授权的控制,其创建了Ingress用到的ServiceAccount、ClusterRole、Role、RoleBinding、ClusterRoleBinding
5.with-rbac.yaml
是Ingress的核心,用于创建ingress-controller。前面提到过,ingress-controller的作用是将新加入的Ingress进行转化为Nginx的配置
方式一:Nodeport方式
mandatory.yaml 中的镜像可修改成国内镜像: 例如: - registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64 - registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller
Copy # 下载yaml文件并更新mandatory.yaml中的镜像地址(master上)若国内服务器: 需替换下镜像地址
mkdir ingress-nginx && cd ingress-nginx
wget https://github.com/kubernetes/ingress-nginx/blob/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://github.com/deploy/static/provider/baremetal/service-nodeport.yaml # nodeport 方式需要额外使用这个文件
# 编辑 service-nodeport.yaml, 添加两行,分别在 http、https下,意思是暴露对外端口
nodePort: 32080 #http
nodePort: 32443 #https
# 运行部署上面两个文件
kubectl apply -f mandatory.yaml
kubectl apply -f service-nodeport.yaml
helm 创建工作环境
Copy [root@k8s-master]# helm create mychart
[root@k8s-master]# rm -f mychart/templates/ *
[root@k8s-master mychart]# tree
.
├── charts
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── ingress.yaml
│ └── service.yaml
└── values.yaml < 暂没写变量,测试使 用 >
depoyment.yaml
Copy ### cat deployment.yaml
apiVersion : v1
kind : Namespace
metadata :
name : mytest
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : myapp
namespace : mytest
labels :
app : myapp
spec :
replicas : 1
selector :
matchLabels :
app : myapp
template :
metadata :
labels :
app : myapp
spec :
containers :
- name : myapp
image : nginx
ports :
- containerPort : 80
name : http
protocol : TCP
service.yaml
Copy # cat service.yaml
apiVersion : v1
kind : Service
metadata :
name : myapp-svc
namespace : mytest
spec :
selector :
app : myapp
ports :
- port : 80
protocol : TCP
targetPort : 80
Ingress.yaml
Copy # cat ingress.yaml
apiVersion : networking.k8s.io/v1beta1
kind : Ingress
metadata :
name : myapp-ingress
namespace : mytest
spec :
rules :
- host : myapp.com
http :
paths :
- path : /
backend :
serviceName : myapp-svc
servicePort : 80
helm 部署
Copy helm install ./mychart --generate-name
访问: myapp.com:32080
方式二:deamonset方式
deamonset方式与nodeport方式只有一处不同,只修改mandatory.yaml,而且,service-nodeport.yaml也不用配置,其他不用修改,访问的时候,直接域名访问,不用加nodeport。
9. Yaml格式的pod定义文件完整内容
Copy apiVersion : v1 #必选,版本号,例如v1
kind : Pod #必选,Pod
metadata : #必选,元数据
name : string #必选,Pod名称
namespace : string #必选,Pod所属的命名空间
labels : #自定义标签
- name : string #自定义标签名字
annotations : #自定义注释列表
- name : string
spec : #必选,Pod中容器的详细定义
containers : #必选,Pod中容器列表
- name : string #必选,容器名称
image : string #必选,容器的镜像名称
imagePullPolicy : [ Always | Never | IfNotPresent ] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
command : [ string ] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args : [ string ] #容器的启动命令参数列表
workingDir : string #容器的工作目录
volumeMounts : #挂载到容器内部的存储卷配置
- name : string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath : string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly : boolean #是否为只读模式
ports : #需要暴露的端口库号列表
- name : string #端口号名称
containerPort : int #容器需要监听的端口号
hostPort : int #容器所在主机需要监听的端口号,默认与Container相同
protocol : string #端口协议,支持TCP和UDP,默认TCP
env : #容器运行前需设置的环境变量列表
- name : string #环境变量名称
value : string #环境变量的值
resources : #资源限制和请求的设置
limits : #资源限制的设置
cpu : string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory : string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests : #资源请求的设置
cpu : string #Cpu请求,容器启动的初始可用数量
memory : string #内存清楚,容器启动的初始可用数量
livenessProbe : #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
exec : #对Pod容器内检查方式设置为exec方式
command : [ string ] #exec方式需要制定的命令或脚本
httpGet : #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path : string
port : number
host : string
scheme : string
HttpHeaders :
- name : string
value : string
tcpSocket : #对Pod内个容器健康检查方式设置为tcpSocket方式
port : number
initialDelaySeconds : 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds : 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds : 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold : 0
failureThreshold : 0
securityContext :
privileged:false
restartPolicy : [ Always | Never | OnFailure ]# Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
nodeSelector : obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
imagePullSecrets : #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name : string
hostNetwork:false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes : #在该pod上定义共享存储卷列表
- name : string #共享存储卷名称 (volumes类型有很多种)
emptyDir : {} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath : string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path : string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret : #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
scretname : string
items :
- key : string
path : string
configMap : #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name : string
items :
- key : string
10. NFS
10.1 服务端
Copy yum -y install nfs-utils rpcbind
systemctl start rpcbind nfs
systemctl enable rpcbind nfs
rpcinfo -p localhost # 查看nfs服务是否安装正常
# 比如我们在服务端的共享目录为/nfs-share,接着输入以下命令配置共享目录, 并使共享目录生效
echo "/nfs-share *(rw,async,no_root_squash)" >> /etc/exports
exportfs -r
systemctl restart rpcbind nfs
# 测试, 若不在一个VPC下,需开放: 111(TCP|UDP) 、20048(TCP|UDP) 、2049(TCP)
showmount -e localhost 或者 showmount -e 公网ip
10.2 客户端
Copy yum install nfs-utils rpcbind -y
systemctl start rpcbind nfs
systemctl enable rpcbind nfs
# 命令挂载
mount -t nfs IP:/nfs-share /client-dir
# /etc/fstab
IP:/nfs-share /client-dir nfs default 0 0
11. StorageClass
11.1 流程
创建Service Account.这是用来管控NFS provisioner在k8s集群中运行的权限
创建StorageClass.负责建立PVC并调用NFS provisioner进行预定的工作,并让PV与PVC建立管理
创建NFS provisioner.有两个功能,一个是在NFS共享目录下创建挂载点(volume),另一个则是建了PV并将PV与NFS的挂载点建立关联
11.2 访问模式和回收策略
访问模式
Copy RWO ReadWriteOnce -- 该volume只能被单个节点以读写的方式映射
ROX ReadOnlyMany -- 该volume可以被多个节点以只读方式映射
RWX ReadWriteMany -- 该volume可以被多个节点以读写的方式映射
回收策略
Copy Retain:保留,需要手动回收 < 推荐这种模式 >
Recycle:回收,自动删除卷中数据
Delete:删除,相关联的存储资产,如AWS EBS,GCE PD,Azure Disk,or OpenStack Cinder卷都会被删除
状态
Copy Available: 空闲的资源,未绑定给PVC
Bound: 绑定给了某个PVC
Released: PVC已经删除了,但是PV还没有被集群回收
Failed: PV在自动回收中失败了
命令行可以显示PV绑定的PVC名称。
11.3 NFS 静态方式 PV
集群管理员创建多个PV,它们携带着真实存储的详细信息,这些存储对于集群用户是可用的。它们存在于Kubernetes API中,并可用于存储使用。
Copy # 环境: kubernetes 1.18.3, 例如文件: test.yaml
apiVersion : v1
kind : Namespace
metadata :
name : mytest
---
apiVersion : v1
kind : PersistentVolume
metadata :
name : nfs-pv # PV 不需要绑定名称空间
labels :
pv : nfs-pv
spec :
capacity :
storage : 1Gi
volumeMode : Filesystem
accessModes :
- ReadWriteMany # 访问模式
persistentVolumeReclaimPolicy : Retain # 回收策略
storageClassName : nfs # storageClassName 定义的名字,为了pvc匹配
nfs :
path : /nfs/data # NFS 共享目录
server : 192.168.1.33 # NFS 共享地址
---
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : nfs-pvc
namespace : mytest
spec :
storageClassName : nfs # 对应上面创建 PV 的 storageClassName名字
accessModes :
- ReadWriteMany
resources :
requests :
storage : 1Gi
---
apiVersion : v1
kind : Pod
metadata :
name : mypod
namespace : mytest
spec :
containers :
- name : nginx
image : nginx
volumeMounts :
- mountPath : /usr/share/nginx/html
name : nfs-pv # 对应上面创建 PV 的名字
volumes :
- name : nfs-pv # 对应上面创建 PV 的名字
persistentVolumeClaim :
claimName : nfs-pvc # 对应上面创建 PVC 的名字
Copy kubectl apply -f test.yaml
kubectl get pv,pvc,pods -n mytest
```
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/nfs-pv 1Gi RWX Retain Bound mytest/nfs-pvc nfs 16m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/nfs-pvc Bound nfs-pv 1Gi RWX nfs 16m
NAME READY STATUS RESTARTS AGE
pod/mypod 1/1 Running 0 16m
```
# 共享目录中创建 index.html 文件,查看 Pod 中是否存在
kubectl exec -it mypod -n mytest -- more /usr/share/nginx/html/index.html
11.4 NFS 动态方式 PV
当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。这种供给基于StorageClass。
参考: https://www.jianshu.com/p/15260a66cd41
Copy # 所有work节点安装 nfs-utils rpcbind
yum install nfs-utils rpcbind -y
systemctl start nfs rpcbind
systemctl enable nfs rpcbind
11.4-1 创建RBAC授权
Copy wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/rbac.yaml
kubectl apply -f rbac.yaml
11.4-2 创建 Storageclass
Copy # cat class.yaml ---> kubectl apply -f storageclass-nfs.yaml
apiVersion : storage.k8s.io/v1
kind : StorageClass
metadata :
name : managed-nfs-storage
provisioner : fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters :
archiveOnDelete : "false"
11.4-3 创建nfs-client-provisioner自动配置程序,以便自动创建持久卷(PV)
自动创建的 PV 以 {namespace}-${pvcName}-${pvName} 的命名格式创建在 NFS 上 当这个 PV 被回收后会以 archieved-{namespace}-${pvcName}-${pvName} 的命名格式存在 NFS 服务器上
Copy # cat deployment.yaml ---> kubectl apply -f deployment.yaml
apiVersion : apps/v1
kind : Deployment
metadata :
name : nfs-client-provisioner
labels :
app : nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace : default
spec :
replicas : 1
strategy :
type : Recreate
selector :
matchLabels :
app : nfs-client-provisioner
template :
metadata :
labels :
app : nfs-client-provisioner
spec :
serviceAccountName : nfs-client-provisioner
containers :
- name : nfs-client-provisioner
image : quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts :
- name : nfs-client-root
mountPath : /persistentvolumes
env :
- name : PROVISIONER_NAME
value : fuseim.pri/ifs
- name : NFS_SERVER
value : 192.168.1.33
- name : NFS_PATH
value : /nfs/data
volumes :
- name : nfs-client-root
nfs :
server : 192.168.1.33
path : /nfs/data
11.4-4 创建一个有状态应用
Copy # cat statefulset-nfs.yaml ---> kubectl apply -f statefulset-nfs.yaml
apiVersion : v1
kind : Service
metadata :
name : nginx
labels :
app : nginx
spec :
ports :
- port : 80
name : web
clusterIP : None
selector :
app : nginx
---
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : nfs-web
spec :
serviceName : "nginx"
replicas : 3
selector :
matchLabels :
app : nfs-web # has to match .spec.template.metadata.labels
template :
metadata :
labels :
app : nfs-web
spec :
terminationGracePeriodSeconds : 10
containers :
- name : nginx
image : nginx:1.7.9
ports :
- containerPort : 80
name : web
volumeMounts :
- name : www
mountPath : /usr/share/nginx/html
volumeClaimTemplates :
- metadata :
name : www
annotations :
volume.beta.kubernetes.io/storage-class : managed-nfs-storage
spec :
accessModes : [ "ReadWriteOnce" ]
resources :
requests :
storage : 1Gi
查看 Pod/PV/PVC
Copy kubectl get pods
kubectl get pvc,pv
# 查看 nfs server 目录中信息,同时各子目录中内容为空
ls -l /data/nfs/
11.4-5 破坏性测试
Copy # 在每个 pod 中写入内容
for i in 0 1 2 ; do kubectl exec nfs-web- $i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html' ; done
# 远程nfs各子目录中不再为空,出现了内容
ls /data/nfs/default-www-nfs-web-0-pvc-62f4868f-c6f7-459e-a280-26010c3a5849/
# 查看每个容器中内容,均为各自主机名
for i in 0 1 2 ; do kubectl exec -it nfs-web- $i -- cat /usr/share/nginx/html/index.html ; done
nfs-web-0
nfs-web-1
nfs-web-2
# 删除对应 pod
kubectl get pod -l app=nfs-web
kubectl delete pod -l app=nfs-web
# 再次查看,会发现会自动创建
kubectl get pod -l app=nfs-web
# 再次查看每个pod中内容,可以看到文件内容没有变化
for i in 0 1 2 ; do kubectl exec -it nfs-web- $i -- cat /usr/share/nginx/html/index.html ; done
nfs-web-0
nfs-web-1
nfs-web-2
11.4-6 结束语
可以看到, statefulset 控制器通过固定的 pod 创建顺序可以确保 pod 之间的拓扑关系一直处于稳定不变的状态,通过 nfs-client-provisioner 自动创建和每个 pod 有固定对应关系的远程存储卷,确保 pod 重建后数据不会丢失。
第四部分 部署统一日志管理
第五部分 部署性能监控平台
第六部分 搭建高可用的K8S集群
第七部分 K8S集群部署项目
第八部分 Ceph 集群
1、Cepy-deploy 部署
1、初始化(所有主机)
Copy sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
systemctl disable firewalld
systemctl stop firewalld
yum -y install ntp
systemctl enable ntpd
systemctl start ntpd
systemctl disable chronyd
ntpq -p
yum install wget -y
mkdir /tmp/repo.bak && mv /etc/yum.repos.d/*.repo /tmp/repo.bak
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -P /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
cat > /etc/yum.repos.d/ceph.repo << EOF
[ceph]
name=ceph
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/x86_64/
gpgcheck=0
[ceph-noarch]
name=cephnoarch
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/noarch/
gpgcheck=0
[ceph-source]
name=ceph-source
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/SRPMS/
gpgcheck=0
EOF
yum clean all
yum makecache
yum -y install python-setuptools
2、主机免密
Copy # cephnode01 执行,作为管理控制节点
ssh-keygen -t rsa -P ""
ssh-copy-id 192.168.110.59
ssh-copy-id 192.168.110.62
ssh-copy-id 192.168.110.64
# 设置 hostname
hostnamectl set-hostname < hostnam e >
# 拷贝 hosts 到远程
echo "192.168.110.59 cephnode01" >> /etc/hosts
echo "192.168.110.62 cephnode02" >> /etc/hosts
echo "192.168.110.64 cephnode03" >> /etc/hosts
yum -y install ceph-deploy
ceph-deploy --version (必须是 2.0.1 + )
3、创建一个my-cluster目录,所有命令在此目录下进行(文件位置和名字可以随意)
Copy mkdir /my-cluster
cd /my-cluster
4、创建一个Ceph集群,(hosts里的解析名和主机名一定要想相同,否则报错)
Copy ceph-deploy new cephnode01 cephnode02 cephnode03
5、安装Ceph软件(每个节点执行)
Copy yum -y install epel-release
yum install -y ceph
# 或者管理节点执行: ceph-deploy install cephnode01 cephnode02 cephnode03
6、初始化,并生成monitor检测集群所使用的的秘钥
Copy ceph-deploy mon create-initial
7、安装Ceph CLI,方便执行一些管理命令
Copy ceph-deploy admin cephnode01 cephnode02 cephnode03
8、配置mgr,用于管理集群
Copy ceph-deploy mgr create cephnode01 cephnode02 cephnode03
9、部署rgw
Copy yum install -y ceph-radosgw
ceph-deploy rgw create cephnode01
10、部署MDS(CephFS)
Copy ceph-deploy mds create cephnode01 cephnode02 cephnode03
11、添加osd
Copy ceph-deploy osd create --data /dev/sdb node1
ceph-deploy osd create --data /dev/sdb node2
ceph-deploy osd create --data /dev/sdb node3
# 注意 如果要在LVM卷上创建OSD,则参数 --data 必须是volume_group/lv_name,而不是卷的块设备的路径。
12、检查集群健康(node1)
Copy [root@localhost my-cluster]# ceph health
HEALTH_OK
[root@localhost my-cluster]# ceph -s
cluster:
id: 0e3f5736-d67b-47af-bac7-7146f7c7a8b5
health: HEALTH_OK
services:
mon: 3 daemons, quorum cephnode03,cephnode02,cephnode01
mgr: cephnode01 ( active ) , standbys: cephnode02, cephnode03
osd: 3 osds: 3 up, 3 in
rgw: 1 daemon active
data:
pools: 4 pools, 32 pgs
objects: 219 objects, 1.09KiB
usage: 3.00GiB used, 27.0GiB / 30.0GiB avail
pgs: 32 active+clean
2、ceph.conf
1、该配置文件采用init文件语法,#和;为注释,ceph集群在启动的时候会按照顺序加载所有的conf配置文件。 配置文件分为以下几大块配置。
Copy global:全局配置。
osd:osd专用配置,可以使用osd.N,来表示某一个OSD专用配置,N为osd的编号,如0、2、1等。
mon:mon专用配置,也可以使用mon.A来为某一个monitor节点做专用配置,其中A为该节点的名称,ceph-monitor-2、ceph-monitor-1等。使用命令 ceph mon dump可以获取节点的名称。
client:客户端专用配置。
2、配置文件可以从多个地方进行顺序加载,如果冲突将使用最新加载的配置,其加载顺序为。
Copy $CEPH_CONF环境变量
-c 指定的位置
/etc/ceph/ceph.conf
~ /.ceph/ceph.conf
./ceph.conf
3、配置文件还可以使用一些元变量应用到配置文件,如。
Copy $cluster:当前集群名。
$type:当前服务类型。
$id:进程的标识符。
$host:守护进程所在的主机名。
$name:值为$type.$id。
4、ceph.conf详细参数
Copy [global]#全局设置
fsid = xxxxxxxxxxxxxxx #集群标识ID
mon host = 10.0.1.1,10.0.1.2,10.0.1.3 #monitor IP 地址
auth cluster required = cephx #集群认证
auth service required = cephx #服务认证
auth client required = cephx #客户端认证
osd pool default size = 3 #最小副本数 默认是3
osd pool default min size = 1 #PG 处于 degraded 状态不影响其 IO 能力,min_size是一个PG能接受IO的最小副本数
public network = 10.0.1.0/24 #公共网络(monitorIP段)
cluster network = 10.0.2.0/24 #集群网络
max open files = 131072 #默认0#如果设置了该选项,Ceph会设置系统的max open fds
mon initial members = node1, node2, node3 #初始monitor (由创建monitor命令而定)
##############################################################
[mon]
mon data = /var/lib/ceph/mon/ceph- $id
mon clock drift allowed = 1 #默认值0.05#monitor间的clock drift
mon osd min down reporters = 13 #默认值1#向monitor报告down的最小OSD数
mon osd down out interval = 600 #默认值300 #标记一个OSD状态为down和out之前ceph等待的秒数
##############################################################
[osd]
osd data = /var/lib/ceph/osd/ceph- $id
osd mkfs type = xfs #格式化系统类型
osd max write size = 512 #默认值90 #OSD一次可写入的最大值(MB)
osd client message size cap = 2147483648 #默认值100 #客户端允许在内存中的最大数据(bytes)
osd deep scrub stride = 131072 #默认值524288 #在Deep Scrub时候允许读取的字节数(bytes)
osd op threads = 16 #默认值2 #并发文件系统操作数
osd disk threads = 4 #默认值1 #OSD密集型操作例如恢复和Scrubbing时的线程
osd map cache size = 1024 #默认值500 #保留OSD Map的缓存(MB)
osd map cache bl size = 128 #默认值50 #OSD进程在内存中的OSD Map缓存(MB)
osd mount options xfs = "rw,noexec,nodev,noatime,nodiratime,nobarrier" #默认值rw,noatime,inode64 #Ceph OSD xfs Mount选项
osd recovery op priority = 2 #默认值10 #恢复操作优先级,取值1-63,值越高占用资源越高
osd recovery max active = 10 #默认值15 #同一时间内活跃的恢复请求数
osd max backfills = 4 #默认值10 #一个OSD允许的最大backfills数
osd min pg log entries = 30000 #默认值3000 #修建PGLog是保留的最大PGLog数
osd max pg log entries = 100000 #默认值10000 #修建PGLog是保留的最大PGLog数
osd mon heartbeat interval = 40 #默认值30 #OSD ping一个monitor的时间间隔(默认30s)
ms dispatch throttle bytes = 1048576000 #默认值 104857600 #等待派遣的最大消息数
objecter inflight ops = 819200 #默认值1024 #客户端流控,允许的最大未发送io请求数,超过阀值会堵塞应用io,为0表示不受限
osd op log threshold = 50 #默认值5 #一次显示多少操作的log
osd crush chooseleaf type = 0 #默认值为1 #CRUSH规则用到chooseleaf时的bucket的类型
##############################################################
[client]
rbd cache = true #默认值 true #RBD缓存
rbd cache size = 335544320 #默认值33554432 #RBD缓存大小(bytes)
rbd cache max dirty = 134217728 #默认值25165824 #缓存为write-back时允许的最大dirty字节数(bytes),如果为0,使用write-through
rbd cache max dirty age = 30 #默认值1 #在被刷新到存储盘前dirty数据存在缓存的时间(seconds)
rbd cache writethrough until flush = false #默认值true #该选项是为了兼容linux-2.6.32之前的virtio驱动,避免因为不发送flush请求,数据不回写
#设置该参数后,librbd会以writethrough的方式执行io,直到收到第一个flush请求,才切换为writeback方式。
rbd cache max dirty object = 2 #默认值0 #最大的Object对象数,默认为0,表示通过rbd cache size计算得到,librbd默认以4MB为单位对磁盘Image进行逻辑切分
#每个chunk对象抽象为一个Object;librbd中以Object为单位来管理缓存,增大该值可以提升性能
rbd cache target dirty = 235544320 #默认值16777216 #开始执行回写过程的脏数据大小,不能超过 rbd_cache_max_dirty
扩展群集
启动并运行基本群集后,下一步是展开群集。添加Ceph元数据服务器node1。然后添加Ceph Monitor和Ceph Manager node2,node3以提高可靠性和可用性。添加元数据服务器:配置MDS服务(NODE1)要使用CephFS,您至少需要一个元数据服务器。执行以下操作以创建元数据服务器:
Copy ceph-deploy mds create node1
添加监视器
Ceph存储集群需要至少运行一个Ceph Monitor和Ceph Manager。为了实现高可用性,Ceph存储集群通常运行多个Ceph监视器,因此单个Ceph监视器的故障不会导致Ceph存储集群崩溃。Ceph使用Paxos算法,该算法需要大多数监视器(即,大于N / 2,其中N是监视器的数量)才能形成法定人数。虽然这不是必需的,但监视器的数量往往更好。
Copy # 将两个Ceph监视器添加到您的群集:
ceph-deploy mon add node2 node3
# 一旦你添加了新的Ceph监视器,Ceph将开始同步监视器并形成一个法定人数。您可以通过执行以下操作来检查仲裁状态:
ceph quorum_status --format json-pretty
# 注意: 当您使用多个监视器运行Ceph时,您应该在每个监视器主机上安装和配置NTP, 确保监视器是NTP对等方。
添加管理员
Ceph Manager守护进程以活动/备用模式运行。部署其他管理器守护程序可确保在一个守护程序或主机发生故障时,另一个守护程序或主机可以在不中断服务的情况下接管。
Copy # 要部署其他管理器守护程序:
ceph-deploy mgr create node2 node3
# 删除OSD(node1)
ceph auth del osd.0
ceph osd rm 0
配置DashBoard
Copy # 创建域管理秘钥(node1)
ceph auth get-or-create mgr.node1 mon 'allow profile mgr' osd 'allow *' mds 'allow *'
# 开启ceph-mgr管理域(node1)
ceph-mgr -i node1
# 打开dashboard模块(node1)
ceph mgr module enable dashboard
# 绑定开启dashboard模块的ceph-mgr节点的ip地址(node1主机)
ceph config-key set mgr/dashboard/node1/server_addr 192.168.110.59
# 访问Dashboard (任意主机)
http://192.168.110.59:7000
常用命令整理
创建 Pool 池
Copy # 注意:创建了池后,无法减少PG的数量,只能增加
[root@localhost ~ ]# ceph osd pool create testPool 16 16
pool 'testPool' created
为 池 启用ceph应用,并指定池类型
Copy # <rbd(块) |cephfs(文件) |object(对象)>
[root@localhost ~ ]# ceph osd pool application enable testPool rbd
enabled application 'testPool' on pool 'testPool'
查看所有池, 或者命令: rados lspools
Copy [root@localhost ~ ]# ceph osd pool ls
.rgw.root
default.rgw.control
default.rgw.meta
default.rgw.log
pool01
testPool
查看所有池的详细信息
Copy [root@localhost ~ ]# ceph osd pool ls detail
pool 1 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 3 flags hashpspool stripe_width 0 application rgw
pool 2 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 17 flags hashpspool stripe_width 0 application rgw
pool 3 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 19 flags hashpspool stripe_width 0 application rgw
pool 4 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 21 flags hashpspool stripe_width 0 application rgw
pool 9 'pool01' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 57 flags hashpspool stripe_width 0 application pool01
removed_snaps [1~3]
pool 11 'testPool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 68 flags hashpspool stripe_width 0 application rbd
修改池名字
Copy [root@localhost ~ ]# ceph osd pool rename testPool testPool1
pool 'testPool' renamed to 'testPool1'
设置 池 配额,限制对象数量
Copy [root@localhost ~ ]# ceph osd pool set-quota testPool max_objects 1024
set-quota max_objects = 1024 for pool testPool
设置 池 配额,限制容量数量
Copy [root@localhost ~ ]# ceph osd pool set-quota testPool max_bytes 1024
set-quota max_bytes = 1024 for pool testPool
取消配额,max_objects 一样
Copy [root@localhost ~ ]# ceph osd pool set-quota testPool max_bytes 0
set-quota max_bytes = 0 for pool testPool
查看池 状态,
Copy [root@localhost ~ ]# ceph osd pool stats
pool .rgw.root id 1
nothing is going on
查看某个池: ceph osd pool stats testPool
创建一个块设备
Copy [root@localhost ~ ]# rbd create --size 1024 block -p testPool
查看池中,有哪些块设备
Copy [root@localhost ~ ]# rbd ls -p testPool
block
查看块设备详细信息
Copy [root@localhost ~ ]# rbd info block -p testPool
rbd image 'block' :
size 2GiB in 512 objects
order 22 (4MiB objects )
block_name_prefix: rbd_data.122616b8b4567
format: 2
features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
flags:
create_timestamp: Sat Apr 17 22:08:50 2021
查看池使用情况
Copy [root@localhost ~ ]# ceph df
GLOBAL:
SIZE AVAIL RAW USED %RAW USED
30.0GiB 27.0GiB 3.01GiB 10.03
POOLS:
NAME ID USED %USED MAX AVAIL OBJECTS
.rgw.root 1 1.09KiB 0 8.49GiB 4
default.rgw.control 2 0B 0 8.49GiB 8
default.rgw.meta 3 0B 0 8.49GiB 0
default.rgw.log 4 0B 0 8.49GiB 207
pool01 9 232B 0 8.49GiB 6
testPool 10 134B 0 8.49GiB 5
查看集群空间使用情况
Copy [root@localhost ~ ]# ceph osd df
ID CLASS WEIGHT REWEIGHT SIZE USE DATA OMAP META AVAIL %USE VAR PGS
0 ssd 0.00980 1.00000 10.0GiB 1.00GiB 2.48MiB 0B 1GiB 8.99GiB 10.03 1.00 64
1 ssd 0.00980 1.00000 10.0GiB 1.00GiB 2.48MiB 0B 1GiB 8.99GiB 10.03 1.00 64
2 ssd 0.00980 1.00000 10.0GiB 1.00GiB 2.48MiB 0B 1GiB 8.99GiB 10.03 1.00 64
TOTAL 30.0GiB 3.01GiB 7.45MiB 0B 3GiB 27.0GiB 10.03
MIN/MAX VAR: 1.00/1.00 STDDEV: 0
### 查看池属性
Copy [root@localhost ~ ]# ceph osd pool get testPool all
size: 3
min_size: 2
crash_replay_interval: 0
pg_num: 16
pgp_num: 16
crush_rule: replicated_rule
hashpspool: true
nodelete: false
nopgchange: false
nosizechange: false
write_fadvise_dontneed: false
noscrub: false
nodeep-scrub: false
use_gmt_hitset: 1
auid: 0
fast_read: 0
对接 k8s 集群:Rbd 持久化存储 <已验证>
准备工作: 创建pod时,kubelet需要使用rbd命令去检测和挂载pv对应的ceph image,所以要在所有的worker节点安装ceph客户端ceph-common。 将ceph的ceph.client.admin.keyring和ceph.conf文件拷贝到master的/etc/ceph目录下
Copy yum -y install ceph-common
1、Ceph集群中,创建一个 pool 池,为后面k8s接入使用
Copy ceph osd pool create kube 128 128
ceph osd pool ls
2、首先得在kubernetes集群中安装 rbd-provisioner ,github仓库链接https://github.com/kubernetes-incubator/external-storage
Copy # 根据自己需要,修改rbd-provisioner的namespace;
yum install git -y
git clone https://github.com/kubernetes-retired/external-storage.git
cd external-storage/ceph/rbd/deploy
export NAMESPACE = kube-system
sed -r -i "s/namespace: [^ ]+/namespace: $NAMESPACE/g" ./rbac/clusterrolebinding.yaml ./rbac/rolebinding.yaml
kubectl -n $NAMESPACE apply -f ./rbac
# 部署完成后检查rbd-provisioner deployment,确保已经正常部署;
kubectl get deploy -n kube-system
kubectl describe deployments.apps -n kube-system rbd-provisioner
3、创建storageclass
创建secret保存client.admin和client.kube用户的key,client.admin和client.kube用户的secret可以放在kube-system namespace,但如果其他namespace需要使用ceph rbd的dynamic provisioning功能的话,要在相应的namespace创建secret来保存client.kube用户key信息
Copy # 部署完rbd-provisioner,还需要创建StorageClass。创建SC前,我们还需要创建相关用户的secret;
[root@k8s01 ~ ]# vi secrets.yaml
apiVersion: v1
kind: Secret
metadata:
name: ceph-admin-secret
namespace: kube-system
type : "kubernetes.io/rbd"
data:
# ceph auth get-key client.admin | base64
key: QVFCdng4QmJKQkFsSFJBQWl1c1o0TGdOV250NlpKQ1BSMHFCa1E9PQ==
---
apiVersion: v1
kind: Secret
metadata:
name: ceph-secret
namespace: kube-system
type : "kubernetes.io/rbd"
data:
# ceph auth add client.kube mon 'allow r' osd 'allow rwx pool=kube'
# ceph auth get-key client.kube | base64
key: QVFCTHdNRmJueFZ4TUJBQTZjd1MybEJ2Q0JUcmZhRk4yL2tJQVE9PQ==
[root@k8s01 ~ ]# kubectl create -f secrets.yaml
[root@k8s01 ~ ]# vi secrets-default.yaml
apiVersion: v1
kind: Secret
metadata:
name: ceph-secret
type : "kubernetes.io/rbd"
data:
# ceph auth add client.kube mon 'allow r' osd 'allow rwx pool=kube'
# ceph auth get-key client.kube | base64
key: QVFCTHdNRmJueFZ4TUJBQTZjd1MybEJ2Q0JUcmZhRk4yL2tJQVE9PQ==
其他设置和普通的ceph rbd StorageClass一致,但provisioner需要设置为**ceph.com/rbd
**,不是默认的kubernetes.io/rbd
,这样rbd的请求将由rbd-provisioner来处理;
考虑到兼容性,建议尽量关闭rbd image feature,并且kubelet节点的ceph-common版本尽量和ceph服务器端保持一致;
Copy [ root@k8s01 ~ ]# vi ceph-rbd-sc.yaml
apiVersion : storage.k8s.io/v1beta1
kind : StorageClass
metadata :
name : ceph-rbd
annotations :
storageclass.beta.kubernetes.io/is-default-class : "true"
provisioner : ceph.com/rbd
parameters :
monitors : 10.10.181.249:6789,10.10.181.248:6789,10.10.181.247:6789
adminId : admin
adminSecretName : ceph-admin-secret
adminSecretNamespace : kube-system
pool : kube
userId : kube
userSecretName : ceph-secret
fsType : ext4
imageFormat : "2"
imageFeatures : "layering"
[ root@k8s01 ~ ]# kubectl create -f ceph-rbd-sc.yaml
4、测试ceph rbd自动分配
在kube-system和default namespace分别创建pod,通过启动一个busybox实例,将ceph rbd镜像挂载到 /usr/share/busybox
;
Copy [ root@k8s01 ~ ]# vi test-pod.yaml
apiVersion : v1
kind : Pod
metadata :
name : ceph-pod1
spec :
containers :
- name : ceph-busybox
image : busybox
command : [ "sleep" , "60000" ]
volumeMounts :
- name : ceph-vol1
mountPath : /usr/share/busybox
readOnly : false
volumes :
- name : ceph-vol1
persistentVolumeClaim :
claimName : ceph-claim
---
kind : PersistentVolumeClaim
apiVersion : v1
metadata :
name : ceph-claim
spec :
accessModes :
- ReadWriteOnce
resources :
requests :
storage : 2Gi
[ root@k8s01 ~ ]# kubectl create -f test-pod.yaml -n kube-system
pod/ceph-pod1 created
persistentvolumeclaim/ceph-claim created
# < 使用默认空间,会使用刚才创建的 secrets-default.yaml,惹其他空间,则创建其他空间秘钥 >
[ root@k8s01 ~ ]# kubectl create -f test-pod.yaml -n default
pod/ceph-pod1 created
persistentvolumeclaim/ceph-claim created
检查pv和pvc的创建状态,是否都已经创建;
Copy [root@k8s01 ~ ]# kubectl get pvc,pv -n kube-system
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
ceph-claim Bound pvc-ee0f1c35-cef7-11e8-8484-005056a33f16 2Gi RWO ceph-rbd 25s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-ea377cad-cef7-11e8-8484-005056a33f16 2Gi RWO Delete Bound kube-system/ceph-claim ceph-rbd 40s
在ceph服务器上,检查rbd镜像创建情况和镜像的信息;
Copy [root@k8s01 ~ ]# rbd ls --pool kube
kubernetes-dynamic-pvc-ea390cbf-cef7-11e8-aa22-0a580af40202
[root@k8s01 ~ ]# rbd info kube/kubernetes-dynamic-pvc-ea390cbf-cef7-11e8-aa22-0a580af40202
rbd image 'kubernetes-dynamic-pvc-ea390cbf-cef7-11e8-aa22-0a580af40202' :
size 2048 MB in 512 objects
order 22 (4096 kB objects )
block_name_prefix: rbd_data.456876b8b4567
format: 2
features: layering
flags:
create_timestamp: Sat Oct 13 22:54:41 2018
检查busybox内的文件系统挂载和使用情况,确认能正常工作;
Copy [root@k8s01 ~ ]# kubectl exec eph-pod1 -- mount | grep rbd
/dev/rbd0 on /usr/share/busybox type ext4 (rw,seclabel,relatime,stripe=1024,data=ordered)
[root@k8s01 ~ ]# kubectl exec -it ceph-pod1 df | grep rbd
/dev/rbd0 1998672 6144 1976144 0% /usr/share/busybox
测试删除pod能否自动删除pv和pvc,生产环境中谨慎,设置好回收策略;
Copy [root@k8s01 ~ ]# kubectl delete -f test-pod.yaml
pod "ceph-pod1" deleted
persistentvolumeclaim "ceph-claim" deleted
[root@k8s01 ~ ]# kubectl get pv
No resources found.
[root@k8s01 ~ ]# kubectl get pvc
No resources found.
ceph服务器上的rbd image也已清除,自动回收成功;
总结
大部分情况下,我们无需使用rbd provisioner来提供ceph rbd的dynamic provisioning能力。经测试,在OpenShift、Rancher、SUSE CaaS以及本Handbook的二进制文件方式部署,在安装好ceph-common软件包的情况下,定义StorageClass时使用kubernetes.io/rbd
即可正常使用ceph rbd provisioning功能。
参考: https://jimmysong.io/kubernetes-handbook/practice/rbd-provisioner.html
对接k8s集群: Cephfs 持久化存储 <已验证>
准备工作所以work节点:
Copy yum -y install epel-release
yum -y install ceph-common ceph-fuse
# 官方没有cephfs动态卷支持, 使用社区提供的cephfs-provisioner
Copy kubectl create ns cephfs
git clone https://github.com/kubernetes-retired/external-storage.git
cd external-storage/ceph/cephfs/deploy
NAMESPACE = cephfs
sed -r -i "s/namespace: [^ ]+/namespace: $NAMESPACE/g" ./rbac/*.yaml
sed -r -i "N;s/(name: PROVISIONER_SECRET_NAMESPACE.*\n[[:space:]]*)value:.*/\1value: $NAMESPACE/" ./rbac/deployment.yaml
kubectl -n $NAMESPACE apply -f ./rbac
#检查pod 的状态是否正常
kubectl get pods -n cephfs
NAME READY STATUS RESTARTS AGE
cephfs-provisioner-7bf7d44886-wvjz8 1/1 Running 0 4h13m
配置 storageclass 及 Pod 测试
Copy [ root@k8s-master3 deploy ]# cat storageclass-cephfs.yaml
apiVersion : v1
kind : Secret
metadata :
name : ceph-secret-fs
namespace : cephfs
type : kubernetes.io/rbd
data :
# ceph auth get-key client.admin | base64 || sed -n '/key/p' ceph.client.admin.keyring |awk '{print $3}' |base64
key : QVFEenkzbGcyYlhrTHhBQVgvUlNPOEJXUldxQisxT1Q1MlIra2c9PQo=
---
kind : StorageClass
apiVersion : storage.k8s.io/v1
metadata :
name : dynamic-cephfs
namespace : cephfs
provisioner : ceph.com/cephfs
parameters :
monitors : 10.10.181.249:6789,10.10.181.248:6789,10.10.181.247:6789
adminId : admin
adminSecretName : ceph-secret-fs
adminSecretNamespace : cephfs
# claimRoot: /volumes/kubernetes
---
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : cephfs-claim
namespace : cephfs
spec :
accessModes :
- ReadWriteMany
storageClassName : dynamic-cephfs
resources :
requests :
storage : 1Gi
---
kind : Pod
apiVersion : v1
metadata :
name : test-pod
namespace : cephfs
spec :
containers :
- name : test-pod
image : ikubernetes/myapp:v4
volumeMounts :
- name : pvc
mountPath : "/data/cephfs"
volumes :
- name : pvc
persistentVolumeClaim :
claimName : cephfs-claim
查看是否挂载:
Copy [root@k8s-master3 deploy]# kubectl exec -it test-pod -n cephfs -- /bin/sh -c 'df -h |grep ceph-fuse'
ceph-fuse 3.6G 0 3.6G 0% /data/cephfs
验证:
Copy [root@k8s-master3 deploy]# kubectl exec -it test-pod -n cephfs -- /bin/sh -c 'echo cephfs-test > /data/cephfs/test.txt && more /data/cephfs/test.txt'
cephfs-test
- provisioner 该字段指定使用存储卷类型为 kubernetes.io/rbd,注意 kubernetes.io/ 开头为 k8s 内部支持的存储提供者,不同的存储卷提供者类型这里要修改成对应的值。 - adminId | userId 这里需要指定两种 Ceph 角色 admin 和其他 user,admin 角色默认已经有了,其他 user 可以去 Ceph 集群创建一个并赋对应权限值,如果不创建,也可以都指定为 admin。 - adminSecretName 为上边创建的 Ceph 管理员 admin 使用的 ceph-secret-admin。 - adminSecretNamespace 管理员 secret 使用的命名空间,默认 default,如果修改为其他的话,需要修改 ceph-secret- admin.yaml 增加 namespace: other-namespace。
第九部分 常见问题
技巧:无法删除 PV,PVC ?
Copy # 系统内有一个已经不再使用的 PV ,已经删除了与其关联的 Pod 及 PVC ,并对其执行了删除命令,但是无法正常删除,一直出于如下状态:
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-gysl 1Gi RWO Recycle Terminating default/www-vct-statefulset-pvc-gysl-0 managed-nfs-storage 22h
### 解决方法: 更新一个资源的 field(s)
kubectl patch pv pv-nfs-gysl -p '{"metadata":{"finalizers":null}}'
persistentvolume/pv-nfs-gysl patched
kubectl get pv
技巧: 无法删除 Pod ?
Copy kubectl delete pod < Podnam e > -n < namespac e > --force --grace-period=0
# 暴力删除
# 删除default namespace下的pod名为pod-to-be-deleted-0
ETCDCTL_API = 3 etcdctl del /registry/pods/default/pod-to-be-deleted-0
# 删除需要删除的NAMESPACE
etcdctl del /registry/namespaces/NAMESPACENAME < /pr e >
技巧: kubeadm 如何删除节点?
Copy # 1)假设我们需要删除 k8s-node1 这个节点,首先在 master 节点上依次执行以下两个命令:
kubectl drain k8s-node1 --delete-local-data --force --ignore-daemonsets
kubectl delete node k8s-node1
# 执行后通过 kubectl get node 命令可以看到 k8s-node1 已被成功删除:
# 2)接着在 k8s-node1 这个 Node 节点上执行如下命令,这样该节点即完全从 Cluster 中脱离开来:
kubeadm reset
技巧:如何重启Pod?
Deployment 方式下重启 Pod
Copy kubectl delete pod {podname} -n {namespace} # 直接删除pod,让k8s去完成 pod 重建
# 但是如果ReplicaSet 管理的 Pod 对象很多的话,那么要一个个手动删除,会很麻烦,所以可以使用命令来删除 ReplicaSet,
kubectl delete replicaset {rs_name} -n {namespace}
# 也可以通过调整 ReplicaSet 的数量来实现重启,比如先 scale 到 0,然后再 scale 到 1,那么 Pod 也不得不重启,
kubectl scale deployment {deployment} --replicas=0 -n {namespace}
kubectl scale deployment {deployment} --replicas=1 -n {namespace}
使用 YAML 文件重启Pod
Copy # 当我们有 Pod 的 yaml 文件是,可以直接使用 replace 命令,来强制替换 Pod 的API对象,从而实现重启的效果:
kubectl replace --force -f youpod.yaml
# 如果你手头没有 yaml 文件,直接使用的 Pod 对象,我们可以稍微调整一下上面的命令,如下:
kubectl get pod {podname} -n {namespace} -o yaml | kubectl replace --force -f -
莫名被打上污点?
此外,kubernetes 1.6引入了对节点问题的展示.也就是说当满足了特定条件,节点控制器会自动为符合条件的节点添加taint
,以下是一些内置的taint
node.kubernetes.io/not-ready ,节点还没有准备好,对应节点状态Ready
值为false
node.kubernetes.io/unreachable ,节点控制器无法触及节点,对应节点状态ready
值为Unknown
node.kubernetes.io/out-of-disk ,磁盘空间不足
node.kubernetes.io/memory-pressure ,节点存在内存压力
node.kubernetes.io/disk-pressure ,节点磁盘存在压力
node.kubernetes.io/network-unavailable ,节点网络不可用
node.kubernetes.io/unschedulable ,节点不可被调度
node.cloudprovider.kubernetes.io/uninitialized
kubeadm安装的K8s忘记了token或者token过期了怎么办?
例如: 主机名:k8s-master IP地址: 192.168.1.136 端口号: 6443
k8s忘记token?
Copy # 列出token ---> 获取CA公钥的哈希值 ---> 加入集群
TOKEN = $( kubeadm token list | awk -F " " '{print $1}' | tail -n 1 )
HASH = $( openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2> /dev/null | openssl dgst -sha256 -hex | sed 's/^.* //' )
kubeadm join 192.168.1.136:6443 --token ${TOKEN} --discovery-token-ca-cert-hash sha256: ${HASH}
token过期怎么加入k8s集群?
Copy # 重新生成
kubeadm token create --print-join-command
kubeadm token list
k8s.v1.20 NFS 无法动态创建pvc,Pending状态
Using Kubernetes v1.20.0, getting "unexpected error getting claim reference: selfLink was empty, can't make reference" #25
首先nfs正常状态下,并且可以挂载
Copy # 测试创建pvc
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : test-pvc
spec :
storageClassName : nfs-provisioner
accessModes :
- ReadWriteMany
resources :
requests :
storage : 20Gi
必须添加 --feature-gates=RemoveSelfLink=false
在 /etc/kubernetes/manifests/kube-apiserver.yaml
文件内
Copy spec :
containers :
- command :
- kube-apiserver
- --feature-gates=RemoveSelfLink=false