尚硅谷k8s课堂随笔
Last updated
K8S是谷歌在2014年开业的容器化集群管理系统
使用k8s进行容器化应用部署
使用k8s利于应用扩展
k8s目标实施让部署容器化应用更加简洁和高效
Master(主控节点)和 node (工作节点)
master 组件
apiserver ---> 集群统一入口,以 restfull 方式,交给 etcd 存储
scheduler ---> 节点调度,选择node节点应用部署
controller-manager ---> 处理集群中常规后台任务,一个资源对应一个控制器
etcd ---> 存储系统,保存集群相关的数据
node组件
kubelet ---> master 派到 node 节点代理,管理本机容器
kube-proxy ---> 提供网络代理,负载均衡等操作
- Pod
最小的部署单元
一组容器的集合
共享网络
生命周期是短暂的
- controller
确保预期的pod副本数量
无状态应用部署
有状态应用部署
确保所有的 node 运行同一个 pod
一次性任务和定时任务
- Service
定义一组 pod 的访问规则
使用空格做为缩进
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
低版本缩进时不允许使用 Tab 键,只允许使用空格
使用#标识注释,从这个字符一直到行尾,都会被解释器忽略
对象; 键值对集合 -----( 映射/哈希/字典)
name: Tom
age: 18 === hash: {name: Tom, age: 19}
数组; 序列 ?列表
People
- Tom
- Jack === People: [Tom, Jack]
纯量( scalars ), 不可分的值
number: 12.30 浮点数
isSet: true 布尔值
parent: ~ null 用 ~ 表示
iso8601: 2001-12-14t21:59:43.10-05:00 时间采用 iso8601 格式
date: 1976-07-31 日期
字符串可以写成多行,第二行需有一个空格缩减
4.3-1 YAML 必须存在的属性
version
String
api版本,目前v1, 可用kubect api-version查看
kind
String
定的资源类型和角色: 比如 Pod
metadata
Object
元数据对象,固定值 metadata
4.3-2 YAML Spec 主要对象
spec.containers[].imagePullPolicy
String
默认 Always; 定义镜像拉取策略,有Always(总是)、Never(使用本地)、IfNotPresent(如果本地没有就拉取);
spec.containers[].command[]
List
指定容器启动命令,可指定多个,不指定默认使用容器打包的启动命令
spec.containers[].args[]
List
指定容器启动参数,可指定多个
4.3-3 YAML 额外的参数
spec.restarPolicy
String
定义Pod重启策略,可以选择值为Always、OnFailure,默认为Always. Always: Pod一旦终止运行,将重启它。 2.OnFilure ,只有Pod以非零退出码终止时,重启,否则,不重启。 3. Never: Pod终止后,将退出码报告给Mater,不会重启改Pod
spec.nodeSelector
Object
定义Node的Label过滤标签,以key:value格式指定
spec.imagePullSecrets
Object
定义pull镜像是使用secrets名称,以name:secretKey格式指定
4.3-4 举例说明
# 创建一个命名空间 namespace, 创建一个Pod
apiVersion: v1
kind: Namespace
metadata:
name: test
---
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: ningx-containers
image: nginx:latest
kubectl get namespaces # 查看命名空间
kubectl get pods # 查看pod
kubectl describe pods/pod1 # 查看指定pod
expose
将一个资源公开为一个新的 Service
run
在集群中运行一个特定的镜像
set
在对象上设置特定的功能
get
显示一个或多个资源
expian
文档参考资料
rolling-update
对给定的复制控制器滚动更新
scale
扩容或缩容Pod数量,Deployment、ReplicaSet、RC或Job
autoscale
创建一个自动选择扩容和缩容并设置Pod数量
certificate
修改证书资源
cluster-info
显示集群信息
logs
在一个Pod中打印一个容器日志。如果Pod只有一个容器,容器名称是可选的
attach
附加到一个运行的容器
exec
执行命令到容器
port-forward
转发一个或多个本地端口到一个pod
cp
拷贝文件或目录到容器中
patch
使用补丁修改、更新资源的字段
replace
通过文件名或标准输入替换一个资源
convert
不同的API版本直接转换配置文件
label
更新资源上的标签
annotate
更新资源上的注释
1、第一种 使用 kubectl create 命令生成 yaml 文件
kubectl create deploy web --image=nginx -o yaml --dry-run>my.yaml
2、第二中 使用 **kubectl get ** 命令导出yaml文件 ; <适用于已有部署集>
kubectl get deploy <部署集名字> -o yaml --export > my.yaml
# 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实例,并设置变量
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 <pod> -n <命名空间> # 查看pod日志
k8s-master
192.168.1.134
k8s-node01
192.168.1.135
k8s-node02
192.168.1.136
# 关闭防火墙
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.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
所有节点:docker 、kubelet 、kubeam 、kubctl
3.1 安装 Docker
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软件源
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
# 由于版本更新频繁,这里指定版本号部署:
yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
systemctl enable kubelet
kubeadm init命令
# 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
kubeadm join 192.168.1.134:6443 --token pvx7z8.ubvh64gsfv5l5tw0 \
--discovery-token-ca-cert-hash sha256:c65c8e0f8e4f897bfdbe9160f69e380942e4d6e38e6690e435b5d2a4bd0d3294
# 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
# 在Master节点,在Kubernetes集群中创建一个pod,验证是否正常运行:
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc
访问地址:http://NodeIP:Port
k8s-master
192.168.1.134
k8s-node01
192.168.1.135
k8s-node02
192.168.1.136
# 关闭防火墙
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.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
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 创建工作目录
mkdir -p ~/TLS/{etcd,k8s}
cd TLS/etcd
3.2 创建生成 Etcd Ca 证书配置
# 自签证书
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申请文件
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证书
# 生成自签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 配置
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 证书申请文件
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 证书
# 生成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.1 下载安装包
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 拷贝刚才生成的证书
cp ~/TLS/etcd/ca*pem ~/TLS/etcd/server*pem /opt/etcd/ssl/
4.3 创建 etcd配置文件
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
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 节点
# 注意复制过去后,修改下 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
# 启动ETCD集群同时启动二个节点,单节点是无法正常启动的。
systemctl daemon-reload && systemctl start etcd && systemctl enable etcd
4.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.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.1 下载源码包
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
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 加速镜像
mkdir /etc/docker
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
5.4 开机自启
systemctl daemon-reload && systemctl start docker && systemctl enable docker
下载地址: https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md
这里使用版本: v1.18.3 , 下载 server 包,里面啥都有
安装 master 必须组件
6.1 下载二进制包
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/
# 把刚才生成的证书拷贝到配置文件中的路径
cp ~/TLS/k8s/ca*pem ~/TLS/k8s/server*pem /opt/kubernetes/ssl/
6.2 启用 TLS Bootstrapping 机制
# 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
# 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
# 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
# 授权 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
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
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"}
下面还是在 Master 上操作,即同时作为 Worker Node
7.1 创建工作目录并拷贝二进制文件
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
# 之前下载的 k8s server 包
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
# 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
cat > /usr/lib/systemd/system/kubelet.service << EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
[Service]
EnvironmentFile=/opt/kubernetes/cfg/kubelet.conf
ExecStart=/opt/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl start kubelet && systemctl enable kubelet && systemctl status kubelet
# 查看kubelet证书请求
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 <none> 7s v1.18.3 # 注:由于网络插件还没有部署,节点会没有准备就绪 NotReady
7.3 部署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
# 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/
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网络
部署
# 必须是 /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 <none> 41m v1.18.3
授权 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
7.5 增加Worker Node
# 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
Pod
控制器
储存
Sservice
调度器
安全机制RBAC
包管理工具 Helm等等
最小部署单元
包含多个容器(一组容器的集合)
一个pod中容器共享网络命名空间
pod是短暂的
共享网络: 通过Pause容器,把其他业务容器加入到Pansu容器里,让所有业务容器在同一个命名空间中,实现网络共享
共享存储: 引入数据卷 Volumn,使用数据卷进行持久化存储
资源共享
一个pod中多个容器共享存储和网络
生命周期短暂
若Pod节点发生故障,那么该Pod会调度到其他节点,是一个全新的Pod,跟之前的pod无关联
平坦的网络
所有Pod都在同一共享网络地址空间中,每个Pod可以通过其他Pod的IP进行访问
Pending
API Server已经创建该Pod,但Pod中的一个或多个容器还没创建,包括镜像下载过程
Running
Pod内错有容器已创建,且至少一个容器处于运行状态、正在启动或正在重启
Completed
Pod内所有容器均成功执行退出,且不会重启
Faild
Pod内所有容器均已退出,但至少一个容器退出失败
Unknow
由于某种原因无法获取Pod状态,例如网络通信不畅
Always
当容器失效时,由kubelet自动重启该容器
OnFailure
当容器终止运行且退出码不为0,由kubelet自动重启该容器
Never
不论容器运行状态如何, kublete都不会重启该容器
RestartPolicy=Always
RestartPolicy=OnFailure
RestartPolicy=Never
包含一个容器
requests:需求,最低保障;
limits:限制,硬限制; 超过被杀死
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 内存。
livenessProbe (存活检查)
如果检查失败,将杀死容器,根据Pod的 restartPolicy 来操作
readlinessProbe (就绪检查)
如果检查失败, Kubernetes会把Pod从 service endpoint中剔除
httpget
发送HTTP请求,返回200·400范围状态码为成功
exec
执行Shell命令返回状态码是0为成功
tcpSocket
发起 Tcp Socket 建立成功
- 1、 kubect 向 Apiserver 发送创建Pod请求 - 2、Api server 收到请求,生成 YAML 文件,并把YAML信息写入 Etcd 中 - 3、 Scheduler 调度器通过Apiserver 读取 Etcd 信息进行判断,如果是NUll,使用调度算法,分配到资源利用少的节点上,并把更新信息写入 Etcd内, - 4、Node 节点上 的 kubelet 会不停的请求 apiserver,读取Etcd数据,如果编号和自己的相同,则调用 dcokerApi,创建容器
- 硬亲和性: 约束条件必须满足 - 软亲和性: 尝试满足,不保证
支持常用操作符: In NotIn Exists Gt Lt DoesNotExists
影响调度的属性
Pod 资源限制对Pod调用产生影响 ( 设置资源限制过大,会找不到足够资源的node节点)
节点选择器标签影响 Pod 调度 (只可调用到指定标签的节点)
使用场景
专用节点
配置特点、硬件特点
基于 Taint 驱逐
污点值 <常用于master节点> - Noschedule 一定不被调度 - PreferNoSchedule 尽量不被调度 - NoExecute 不会调度,并且驱逐已有的 Pod
# 查看污点
kubectl describe node <节点名字> |grep -i taint
# 为节点添加污点
kubectl taint node <节点名称> key=value:<污点值>
# 删除污点,注意后面要加 -
kubectl taint node <节点名称> key=value:<污点值>-
污点容忍
比如某个节点节点被标记为了污点节点,要想 pod 能够调度到 master 节点去,这个该怎么办?```
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
在集群上管理和运行容器的对象,俗称控制器
Pod 是通过 Controller 实现应用的运维,比如伸缩、滚动升级等等
部署无状态应用
管理 Pod 与 ReplicaSet
部署,滚动升级等功能
------- 主要应用场景: web服务、微服务
# 使用 deployment 部署应用(上下选择标签要相同)
···
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
# 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 <none> 80:31281/TCP 2m56s
# 测试端口访问
curl localhost:31281
# 应用升级版本
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
服务发现
防止与 Pod 的是失联
定义一组Pod 的访问策略 (相当于负载均衡器)
- Pod 类似架构中的 后端服务器, Service 相当于架构中的虚拟 VIP,通过Service实现负载均衡
- Pod 与 Service 根据 Label 和 selector 标签选择器建立关联
1、ClusterIP: 集群内部使用
2、NodePort: 对外访问应用
3、LoadBalancor: 对外访问应用使用,公有云
认为Pod 都是一样的
没有顺序要求
不用考虑在哪个 node 运行
随意进行伸缩和扩展
用于无状态的特点
会让每个Pod独立,保持 Pod 启动顺序和唯一性
唯一的网络标识符,持久存储
有序,比如mysql主从
无头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
例如: 在每个 node 节点上安装数据采集工具
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
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
Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露 到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用
作用: 加密数据存在 etcd 里面, 让 Pod 容器以挂载 Volume 方式镜像访问
场景: 凭证
Service Account :用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中
Opaque : base64 编码格式的 Secret,用来存储密码、密钥等
kubernetes.io/dockerconfigjson :用来存储私有 docker registry 的认证信息
6.2-1 Service Account
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 对象
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中
# 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动态更新。
# 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 的认证信息.
# 使用 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 ##没有则无法访问私有仓库
作用: 存储不加密数据到 etcd, 让Pod以变量或者Volume挂载到容器中 场景: 配置文件
6.3-1 Pod 使用 ConfigMap 方式?
将ConfigMap中的数据设置为环境变量
将ConfigMap中的数据设置为命令行参数
使用Volume将ConfigMap作为文件或目录挂载
注意: - ConfigMap必须在Pod使用它之前创建 - 使用envFrom时,将会自动忽略无效的键 - Pod只能使用同一个命名空间的ConfigMap
6.3-2 创建ConfigMap两种方式
方式(1):命令行方式
kubectl create configmap nginxconfig --from-file /server/yaml/nginx/nginx.conf #通过命令直接创建
kubectl get configmap nginxconfig -o yaml #查看文件
方式(2):YMAL文件方式
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文件
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已经创建.
#---------------------------------------------------------------------------
创建资源服务
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
RBAC 实现机制:基于角色的访问控制
大白话: 白名单机制,想让他具备什么权限,就先创建某个角色Role,然后定制rules,再将某个用户user与role绑定,bind得到这种绑定关系为RoleBind
- Role 权限的集合 - ClusterRole 集群角色 - RoleBinding 角色绑定 - ClusterRoleBinding 集群角色绑定
helm:一个命令行客户端工具,主要用于 Kubernetes 应用 chart 的创建、打包、发 布和管理。
Chart:应用描述,一系列用于描述 k8s 资源相关文件的集合。
Release:基于 Chart 的部署实体,一个 chart 被 Helm 运行后将会生成对应的一个 release;将在 k8s 中创建出真实运行的资源对象。
# 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
create
创建一个chart 并指定名字
dependency
管理 chart 依赖
get
下载一个release.可用子命令: all 、hooks、manifest、notes、values
history
获取 release 历史
install
安装一个 chart
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.1 概述
在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,在Kubernetes 目前 提供了以下几种方案:
- NodePort
- LoadBalancer
- Ingress
# 组成
ingress controller
将新加入的Ingress转化成Nginx的配置文件并使之生效
ingress服务
将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可
9.2 工作原理
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 两种方式
下载部署文件
# 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
# 下载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 创建工作环境
[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
### 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
# 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
# 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 部署
helm install ./mychart --generate-name
访问: myapp.com:32080
方式二:deamonset方式
deamonset方式与nodeport方式只有一处不同,只修改mandatory.yaml,而且,service-nodeport.yaml也不用配置,其他不用修改,访问的时候,直接域名访问,不用加nodeport。
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
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
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
创建一个可用的NFS Serve
创建Service Account.这是用来管控NFS provisioner在k8s集群中运行的权限
创建StorageClass.负责建立PVC并调用NFS provisioner进行预定的工作,并让PV与PVC建立管理
创建NFS provisioner.有两个功能,一个是在NFS共享目录下创建挂载点(volume),另一个则是建了PV并将PV与NFS的挂载点建立关联
访问模式
RWO ReadWriteOnce -- 该volume只能被单个节点以读写的方式映射
ROX ReadOnlyMany -- 该volume可以被多个节点以只读方式映射
RWX ReadWriteMany -- 该volume可以被多个节点以读写的方式映射
回收策略
Retain:保留,需要手动回收 < 推荐这种模式 >
Recycle:回收,自动删除卷中数据
Delete:删除,相关联的存储资产,如AWS EBS,GCE PD,Azure Disk,or OpenStack Cinder卷都会被删除
状态
Available: 空闲的资源,未绑定给PVC
Bound: 绑定给了某个PVC
Released: PVC已经删除了,但是PV还没有被集群回收
Failed: PV在自动回收中失败了
命令行可以显示PV绑定的PVC名称。
集群管理员创建多个PV,它们携带着真实存储的详细信息,这些存储对于集群用户是可用的。它们存在于Kubernetes API中,并可用于存储使用。
# 环境: 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 的名字
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
当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。这种供给基于StorageClass。
参考: https://www.jianshu.com/p/15260a66cd41
# 所有work节点安装 nfs-utils rpcbind
yum install nfs-utils rpcbind -y
systemctl start nfs rpcbind
systemctl enable nfs rpcbind
11.4-1 创建RBAC授权
wget https://raw.githubusercontent.com/kubernetes-incubator/external-storage/master/nfs-client/deploy/rbac.yaml
kubectl apply -f rbac.yaml
11.4-2 创建 Storageclass
# 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 服务器上
# 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 创建一个有状态应用
# 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
kubectl get pods
kubectl get pvc,pv
# 查看 nfs server 目录中信息,同时各子目录中内容为空
ls -l /data/nfs/
11.4-5 破坏性测试
# 在每个 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 重建后数据不会丢失。
192.168.110.59
cephnode01
192.168.110.62
cephnode02
192.168.110.64
cephnode03
1、初始化(所有主机)
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、主机免密
# 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 <hostname>
# 拷贝 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目录,所有命令在此目录下进行(文件位置和名字可以随意)
mkdir /my-cluster
cd /my-cluster
4、创建一个Ceph集群,(hosts里的解析名和主机名一定要想相同,否则报错)
ceph-deploy new cephnode01 cephnode02 cephnode03
5、安装Ceph软件(每个节点执行)
yum -y install epel-release
yum install -y ceph
# 或者管理节点执行: ceph-deploy install cephnode01 cephnode02 cephnode03
6、初始化,并生成monitor检测集群所使用的的秘钥
ceph-deploy mon create-initial
7、安装Ceph CLI,方便执行一些管理命令
ceph-deploy admin cephnode01 cephnode02 cephnode03
8、配置mgr,用于管理集群
ceph-deploy mgr create cephnode01 cephnode02 cephnode03
9、部署rgw
yum install -y ceph-radosgw
ceph-deploy rgw create cephnode01
10、部署MDS(CephFS)
ceph-deploy mds create cephnode01 cephnode02 cephnode03
11、添加osd
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)
[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
1、该配置文件采用init文件语法,#和;为注释,ceph集群在启动的时候会按照顺序加载所有的conf配置文件。 配置文件分为以下几大块配置。
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、配置文件可以从多个地方进行顺序加载,如果冲突将使用最新加载的配置,其加载顺序为。
$CEPH_CONF环境变量
-c 指定的位置
/etc/ceph/ceph.conf
~/.ceph/ceph.conf
./ceph.conf
3、配置文件还可以使用一些元变量应用到配置文件,如。
$cluster:当前集群名。
$type:当前服务类型。
$id:进程的标识符。
$host:守护进程所在的主机名。
$name:值为$type.$id。
4、ceph.conf详细参数
[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,您至少需要一个元数据服务器。执行以下操作以创建元数据服务器:
ceph-deploy mds create node1
Ceph存储集群需要至少运行一个Ceph Monitor和Ceph Manager。为了实现高可用性,Ceph存储集群通常运行多个Ceph监视器,因此单个Ceph监视器的故障不会导致Ceph存储集群崩溃。Ceph使用Paxos算法,该算法需要大多数监视器(即,大于N / 2,其中N是监视器的数量)才能形成法定人数。虽然这不是必需的,但监视器的数量往往更好。
# 将两个Ceph监视器添加到您的群集:
ceph-deploy mon add node2 node3
# 一旦你添加了新的Ceph监视器,Ceph将开始同步监视器并形成一个法定人数。您可以通过执行以下操作来检查仲裁状态:
ceph quorum_status --format json-pretty
# 注意: 当您使用多个监视器运行Ceph时,您应该在每个监视器主机上安装和配置NTP, 确保监视器是NTP对等方。
Ceph Manager守护进程以活动/备用模式运行。部署其他管理器守护程序可确保在一个守护程序或主机发生故障时,另一个守护程序或主机可以在不中断服务的情况下接管。
# 要部署其他管理器守护程序:
ceph-deploy mgr create node2 node3
# 删除OSD(node1)
ceph auth del osd.0
ceph osd rm 0
# 创建域管理秘钥(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
# 注意:创建了池后,无法减少PG的数量,只能增加
[root@localhost ~]# ceph osd pool create testPool 16 16
pool 'testPool' created
# <rbd(块) |cephfs(文件) |object(对象)>
[root@localhost ~]# ceph osd pool application enable testPool rbd
enabled application 'testPool' on pool 'testPool'
[root@localhost ~]# ceph osd pool ls
.rgw.root
default.rgw.control
default.rgw.meta
default.rgw.log
pool01
testPool
[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
[root@localhost ~]# ceph osd pool rename testPool testPool1
pool 'testPool' renamed to 'testPool1'
[root@localhost ~]# ceph osd pool set-quota testPool max_objects 1024
set-quota max_objects = 1024 for pool testPool
[root@localhost ~]# ceph osd pool set-quota testPool max_bytes 1024
set-quota max_bytes = 1024 for pool testPool
[root@localhost ~]# ceph osd pool set-quota testPool max_bytes 0
set-quota max_bytes = 0 for pool testPool
[root@localhost ~]# ceph osd pool stats
pool .rgw.root id 1
nothing is going on
查看某个池: ceph osd pool stats testPool
[root@localhost ~]# rbd create --size 1024 block -p testPool
[root@localhost ~]# rbd ls -p testPool
block
[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
[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
[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
### 查看池属性
[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
准备工作: 创建pod时,kubelet需要使用rbd命令去检测和挂载pv对应的ceph image,所以要在所有的worker节点安装ceph客户端ceph-common。 将ceph的ceph.client.admin.keyring和ceph.conf文件拷贝到master的/etc/ceph目录下
yum -y install ceph-common
1、Ceph集群中,创建一个 pool 池,为后面k8s接入使用
ceph osd pool create kube 128 128
ceph osd pool ls
2、首先得在kubernetes集群中安装 rbd-provisioner,github仓库链接https://github.com/kubernetes-incubator/external-storage
# 根据自己需要,修改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信息
# 部署完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服务器端保持一致;
[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
;[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的创建状态,是否都已经创建;[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镜像创建情况和镜像的信息;[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内的文件系统挂载和使用情况,确认能正常工作;
测试删除pod能否自动删除pv和pvc,生产环境中谨慎,设置好回收策略;
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
准备工作所以work节点:
yum -y install epel-release yum -y install ceph-common ceph-fuse
# 官方没有cephfs动态卷支持, 使用社区提供的cephfs-provisioner
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 测试
[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
查看是否挂载:
[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
验证:
[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 ,已经删除了与其关联的 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
kubectl delete pod <Podname> -n <namespace> --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</pre>
# 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
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}
# 当我们有 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
例如: 主机名:k8s-master IP地址: 192.168.1.136 端口号: 6443
# 列出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}
# 重新生成
kubeadm token create --print-join-command
kubeadm token list
Using Kubernetes v1.20.0, getting "unexpected error getting claim reference: selfLink was empty, can't make reference" #25
首先nfs正常状态下,并且可以挂载
# 测试创建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
文件内
spec:
containers:
- command:
- kube-apiserver
- --feature-gates=RemoveSelfLink=false
metadata.name
String
元数据对象名字
metadata.namespace
String
元数据命名空间
Spec
Object
详细定义对象,固定值写Spec
spec.containers[]
list
这是Spec对象的容器列表定义,是个列表
spec.containers[].name
String
定义容器的名字
spec.containers[].image
String
定义要用到的镜像名称
spec.containers[].workingDir
List
指定容器的工作目录
spec.containers[].volumeMounts[]
List
指定容器内部的存储卷配置
spec.containers[].valumeMounts[].name
String
指定可以被容器挂载的存储卷名称
spec.containers[].valumeMounts[].mountPath
String
指定可以被容器挂载的容器卷的路径
spec.containers[].valumeMounts[].readOnly
String
设置存储卷路径的读写模式,true或者false,默认为读写模式
spec.containers[].ports[]
List
指定容器需要用到的端口列表
spec.containers[].ports[].name
String
指定端口名称
spec.containers[].ports[].containerPort
String
指定容器需要监听的端口号
spec.containers[].ports.hostPort
String
指定容器所在主机需要监听的端口号,默认和 containerPort相同,如果设置了hostport,同一台主机无法启动相同副本,会冲突
spec.containers[].ports[].protocol
String
指定端口协议,TCP/UDP,默认TCP
spec.containers[].env[]
List
指定容器运行时需设置的环境变量列表
spec.containers[].env[].name
String
指定环境变量名称
spec.containers[].env[].value
String
指定环境变量值
spec.containers[].resources
Object
指定资源限制和资源请求的值(资源上限)
spec.containers[].resources.limits
Object
指定设置容器运行时资源的运行上限
spec.containers[].resources.limits.cpu
String
指定CPU限制,单位 core 数,将用于 --cpu-shares 参数
spec.containers[].resources.limits.memory
String
指定MEM内存限制,单位 MIB,GIB
spec.containers[].resources.requests
String
指定容器启动和调度室的限制设置
spec.containers[].resources.requests.cpu
String
CPU请求,单位 core 数,容器启动时初始化可用数量
spec.containers[].resources.requests.memory
String
内存请求,单位MIB,GIB,容器启动时初始化可用数量
spec.hostNetwork
Boolean
定义是否使用主机忘了默认,默认值false,设置true表示使用宿主机忘了,不适用docker网桥,同时设置true将无法在一台宿主机上启动第二个副本
edit
使用默认的编辑器编辑一个资源
delete
通过文件名、标准输入、资源名称或标签选择器来删除资源
top
显示资源(CPU/Memory/Storage)使用
cordon
标记节点不可调度
uncordon
标记节点可调度
drain
驱逐节点上的应用,准备下线维护
taint
修改节点 taint 标记
auth
检查授权
completion
用于实现kubectl工具自动补全
api-version
打印受支持的API版本
config
修改kubeconfig文件(用户访问API,比如配置认证信息)
plugin
运行一个命令行插件
version
打印客户端和服务版本信息
help
帮助
Running
容器成功退出
Running
Successded
Successded
包含一个容器
Running
容器失败退出
Running
Running
Failure
包含两个容器
Running
1个容器失败退出
Running
Running
Running
包含两个容器
Running
容器被OOM杀掉
Running
Running
Failure
list
列出 release
package
将 chart 目录打包到 chart 存档文件中
pull
从远程仓库下载 chart 并解压到本地
repo
添加,列出,移除,更新和索引chart仓库:可用子命令add, index, list, remove, update
rollback
从之前版本回滚
search
根据关键字搜索chart。可用子命令: all, repo
show
查看chart想想信息,可用子命令:all,chart,readme,values
status
显示已命名版本的状态
template
本地呈现摸版
uninstall
卸载一个 release
upgrade
更新一个 release
version
查看helm客户端版本
[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
[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.
rbd ls -p kube