k8s中级班day3
第11章:Pod数据持久化分类:本地卷:hostPath,emptyDir网络卷:nfs,ceph(cephfs,rbd),glusterfs公有云:aws,azurek8s资源:downwardAPI,configMap,secretdownwardAPIstatus.podIP - the pod’s IP addressspec.serviceAccoun...
第11章:Pod数据持久化
分类:
本地卷:hostPath,emptyDir
网络卷:nfs,ceph(cephfs,rbd),glusterfs
公有云:aws,azure
k8s资源:downwardAPI,configMap,secret
downwardAPI
status.podIP - the pod’s IP address
spec.serviceAccountName - the pod’s service account name, available since v1.4.0-alpha.3
spec.nodeName - the node’s name, available since v1.4.0-alpha.3
status.hostIP - the node’s IP, available since v1.7.0-alpha.1
参考文档:https://kubernetes.io/docs/concepts/storage/volumes/
-
Kubernetes中的Volume提供了在容器中挂载外部存储的能力
-
Pod需要设置卷来源(spec.volume)和挂载点(spec.containers.volumeMounts)两个信息后才可以使用相应的Volume
3.1 emptyDir
创建一个空卷,挂载到Pod中的容器。Pod删除该卷也会被删除。
应用场景:Pod中容器之间数据共享
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: write
image: centos
command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
volumeMounts:
- name: data
mountPath: /data
- name: read
image: centos
command: ["bash","-c","tail -f /data/hello"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
emptyDir: {}
docker ps 查看容器名,找到对应POD name 后缀
/var/lib/kubelet/pods/<POD ID>/volumes/kubernetes.io~empty-dir/data
3.2 hostPath
emptyDir == 类似于容器的volume
hostPath == 类似于容器的bindmount 日志采集agent,把容器的日志都挂到宿主机一个目录,然后宿主机跑一个日志采集的agent读这个目录;监控agent,需要获取宿主机/proc里的一些信息
挂载Node文件系统上文件或者目录到Pod中的容器。
应用场景:Pod中容器需要访问宿主机文件
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: busybox
image: busybox
args:
- /bin/sh
- -c
- sleep 36000
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
hostPath:
path: /tmp
type: Directory
验证:进入Pod中的/data目录内容与当前运行Pod的节点内容一样。
3.3 网络存储
no_root_squash:登入 NFS 主机使用分享目录的使用者,如果是 root 的话,那么对于这个分享的目录来说,他就具有 root 的权限!这个项目『极不安全』,不建议使用!
root_squash:在登入 NFS 主机使用分享之目录的使用者如果是 root 时,那么这个使用者的权限将被压缩成为匿名使用者,通常他的 UID 与 GID 都会变成 nobody 那个系统账号的身份;
yum install nfs-utils -y
vi /etc/exports
i/ifs/kubernetes *(rw,no_root_squash)
mkdir -p /ifs/kubernetes
systemctl start nfs
mount -t nfs 10.0.0.200:/ifs/kubernetes /mnt/
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
- image: nginx
name: nginx
resources: {}
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
nfs:
server: 10.0.0.200
path: /ifs/kubernetes
3.4 PV&PVC
**PersistentVolume(PV):**对存储资源创建和使用的抽象,使得存储作为集群中的资源管理
PV供给分为:
-
静态
-
动态
**PersistentVolumeClaim(PVC):**让用户不需要关心具体的Volume实现细节
3.5 PV静态供给
静态供给是指提前创建好很多个PV,以供使用。
先准备一台NFS服务器作为测试。
# yum install nfs-utils
# vi /etc/exports
/ifs/kubernetes *(rw,no_root_squash)
# mkdir -p /ifs/kubernetes
# systemctl start nfs
# systemctl enable nfs
并且要在每个Node上安装nfs-utils包,用于mount挂载时用。
示例:先准备三个PV,分别是5G,10G,20G,修改下面对应值分别创建。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001 # 修改PV名称
spec:
capacity:
storage: 30Gi # 修改大小
accessModes:
- ReadWriteMany
nfs:
path: /ifs/kubernetes/pv001 # 修改目录名
server: 192.168.31.62
mkdir -p /ifs/kubernetes/pv001
创建一个Pod使用PV:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: my-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
创建并查看PV与PVC状态:
# kubectl apply -f pod-pv.yaml
# kubectl get pv,pvc
会发现该PVC会与5G PV进行绑定成功。
然后进入到容器中/usr/share/nginx/html(PV挂载目录)目录下创建一个文件测试:
kubectl exec -it my-pod bash
cd /usr/share/nginx/html
echo "123" index.html
再切换到NFS服务器,会发现也有刚在容器创建的文件,说明工作正常。
cd /opt/nfs/pv001
ls
index.html
如果创建一个PVC为16G,你猜会匹配到哪个PV呢?
https://kubernetes.io/docs/concepts/storage/persistent-volumes/
3.6 PV动态供给
Dynamic Provisioning机制工作的核心在于StorageClass的API对象。
StorageClass声明存储插件,用于自动创建PV。
Kubernetes支持动态供给的存储插件:
https://kubernetes.io/docs/concepts/storage/storage-classes/
3.5 PV动态供给实践(NFS)
工作流程
由于K8S不支持NFS动态供给,还需要先安装上图中的nfs-client-provisioner插件:
https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client/deploy
# cd nfs-client
# vi deployment.yaml # 修改里面NFS地址和共享目录为你的
# kubectl apply -f .
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-df88f57df-bv8h7 1/1 Running 0 49m
测试:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: my-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: "managed-nfs-storage"
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
这次会自动创建5GPV并与PVC绑定。
kubectl get pv,pvc
测试方法同上,进入到容器中/usr/share/nginx/html(PV挂载目录)目录下创建一个文件测试。
再切换到NFS服务器,会发现下面目录,该目录是自动创建的PV挂载点。进入到目录会发现刚在容器创建的文件。
# ls /opt/nfs/
default-my-pvc-pvc-51cce4ed-f62d-437d-8c72-160027cba5ba
第12章:再谈有状态应用部署
1.StatefulSet控制器概述
StatefulSet:
-
部署有状态应用
-
解决Pod独立生命周期,保持Pod启动顺序和唯一性
-
稳定,唯一的网络标识符,持久存储
-
有序,优雅的部署和扩展、删除和终止
-
有序,滚动更新
应用场景:数据库
2.稳定的网络ID
说起StatefulSet稳定的网络标识符,不得不从Headless说起了。
标准Service:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 9376
无头Service(Headless Service):
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
clusterIP: None
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 9376
标准Service与无头Service区别是clusterIP: None,这表示创建Service不要为我(Headless Service)分配Cluster IP,因为我不需要。
为什么标准Service需要?
这就是无状态和有状态的控制器设计理念了,无状态的应用Pod是完全对等的,提供相同的服务,可以在飘移在任意节点,例如Web。而像一些分布式应用程序,例如zookeeper集群、etcd集群、mysql主从,每个实例都会维护着一种状态,每个实例都各自的数据,并且每个实例之间必须有固定的访问地址(组建集群),这就是有状态应用。所以有状态应用是不能像无状态应用那样,创建一个标准Service,然后访问ClusterIP负载均衡到一组Pod上。这也是为什么无头Service不需要ClusterIP的原因,它要的是能为每个Pod固定一个”身份“。
举例说明:
apiVersion: v1
kind: Service
metadata:
name: headless-svc
spec:
clusterIP: None
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "headless-svc"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
相比之前讲的yaml,这次多了一个serviceName: “nginx”字段,这就告诉StatefulSet控制器要使用nginx这个headless service来保证Pod的身份。
# kubectl get pods
NAME READY STATUS RESTARTS AGE
my-pod 1/1 Running 0 7h50m
nfs-client-provisioner-df88f57df-bv8h7 1/1 Running 0 7h54m
web-0 1/1 Running 0 6h55m
web-1 1/1 Running 0 6h55m
web-2 1/1 Running 0 6h55m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/headless-svc ClusterIP None <none> 80/TCP 7h15m
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 8d
临时创建一个Pod,测试DNS解析:
# kubectl run -i --tty --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx.default.svc.cluster.local
Server: 10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
Name: nginx.default.svc.cluster.local
Address 1: 172.17.26.3 web-1.nginx.default.svc.cluster.local
Address 2: 172.17.26.4 web-2.nginx.default.svc.cluster.local
Address 3: 172.17.83.3 web-0.nginx.default.svc.cluster.local
结果得出该Headless Service代理的所有Pod的IP地址和Pod 的DNS A记录。
通过访问web-0.nginx的Pod的DNS名称时,可以解析到对应Pod的IP地址,其他Pod 的DNS名称也是如此,这个DNS名称就是固定身份,在生命周期不会再变化:
/ # nslookup web-0.nginx.default.svc.cluster.local
Server: 10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local
Name: web-0.nginx.default.svc.cluster.local
Address 1: 172.17.83.3 web-0.nginx.default.svc.cluster.local
进入容器查看它们的主机名:
[root@k8s-master01 ~]# kubectl exec web-0 hostname
web-0
[root@k8s-master01 ~]# kubectl exec web-1 hostname
web-1
[root@k8s-master01 ~]# kubectl exec web-2 hostname
web-2
可以看到,每个Pod都从StatefulSet的名称和Pod的序号中获取主机名的。
不过,相信你也已经注意到了,尽管 web-0.nginx 这条记录本身不会变,但它解析到的 Pod 的 IP 地址,并不是固定的。这就意味着,对于“有状态应用”实例的访问,你必须使用 DNS 记录或者 hostname 的方式,而绝不应该直接访问这些 Pod 的 IP 地址。
以下是Cluster Domain,Service name,StatefulSet名称以及它们如何影响StatefulSet的Pod的DNS名称的一些选择示例。
Cluster Domain | Service (ns/name) | StatefulSet (ns/name) | StatefulSet Domain | Pod DNS | Pod Hostname |
---|---|---|---|---|---|
cluster.local | default/nginx | default/web | nginx.default.svc.cluster.local | web-{0…N-1}.nginx.default.svc.cluster.local | web-{0…N-1} |
cluster.local | foo/nginx | foo/web | nginx.foo.svc.cluster.local | web-{0…N-1}.nginx.foo.svc.cluster.local | web-{0…N-1} |
kube.local | foo/nginx | foo/web | nginx.foo.svc.kube.local | web-{0…N-1}.nginx.foo.svc.kube.local | web-{0…N-1} |
3.稳定的存储
StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate 创建一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC。
示例:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "headless-svc"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "managed-nfs-storage"
resources:
requests:
storage: 1Gi
# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv001 5Gi RWX Retain Released default/my-pvc 8h
persistentvolume/pv002 10Gi RWX Retain Available 8h
persistentvolume/pv003 30Gi RWX Retain Available 8h
persistentvolume/pvc-2c5070ff-bcd1-4703-a8dd-ac9b601bf59d 1Gi RWO Delete Bound default/www-web-0 managed-nfs-storage 6h58m
persistentvolume/pvc-46fd1715-181a-4041-9e93-fa73d99a1b48 1Gi RWO Delete Bound default/www-web-2 managed-nfs-storage 6h58m
persistentvolume/pvc-c82ae40f-07c5-45d7-a62b-b129a6a011ae 1Gi RWO Delete Bound default/www-web-1 managed-nfs-storage 6h58m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/www-web-0 Bound pvc-2c5070ff-bcd1-4703-a8dd-ac9b601bf59d 1Gi RWO managed-nfs-storage 6h58m
persistentvolumeclaim/www-web-1 Bound pvc-c82ae40f-07c5-45d7-a62b-b129a6a011ae 1Gi RWO managed-nfs-storage 6h58m
persistentvolumeclaim/www-web-2 Bound pvc-46fd1715-181a-4041-9e93-fa73d99a1b48 1Gi RWO managed-nfs-storage 6h58m
结果得知,StatefulSet为每个Pod分配专属的PVC及编号。每个PVC绑定对应的 PV,从而保证每一个 Pod 都拥有一个独立的 Volume。
在这种情况下,删除Pods或StatefulSet时,它所对应的PVC和PV不会被删除。所以,当这个Pod被重新创建出现之后,Kubernetes会为它找到同样编号的PVC,挂载这个PVC对应的Volume,从而获取到以前保存在 Volume 里的数据。
小结
StatefulSet与Deployment区别:有身份的!
身份三要素:
-
域名
-
主机名
-
存储(PVC)
这里为你准备了一个etcd集群,来感受下有状态部署: https://github.com/lizhenliang/k8s-statefulset/tree/master/etcd
第13章:Kubernetes 鉴权框架与用户权限分配
1.Kubernetes的安全框架
-
访问K8S集群的资源需要过三关:认证、鉴权、准入控制
-
普通用户若要安全访问集群API Server,往往需要证书、Token或者用户名+密码;Pod访问,需要ServiceAccount
-
K8S安全控制框架主要由下面3个阶段进行控制,每一个阶段都支持插件方式,通过API Server配置来启用插件。
访问API资源要经过以下三关才可以:
-
Authentication(鉴权)
-
Authorization(授权)
-
Admission Control(准入控制)
2.传输安全,认证,授权,准入控制
传输安全:
-
告别8080,迎接6443
-
全面基于HTTPS通信
鉴权:三种客户端身份认证:
-
HTTPS 证书认证:基于CA证书签名的数字证书认证
-
HTTP Token认证:通过一个Token来识别用户
-
HTTP Base认证:用户名+密码的方式认证
授权:
RBAC(Role-Based Access Control,基于角色的访问控制):负责完成授权(Authorization)工作。
根据API请求属性,决定允许还是拒绝。
准入控制:
Adminssion Control实际上是一个准入控制器插件列表,发送到API Server的请求都需要经过这个列表中的每个准入控制器插件的检查,检查不通过,则拒绝请求。
3.使用RBAC授权
RBAC(Role-Based Access Control,基于角色的访问控制),允许通过Kubernetes API动态配置策略。
角色
-
Role:授权特定命名空间的访问权限
-
ClusterRole:授权所有命名空间的访问权限
角色绑定
-
RoleBinding:将角色绑定到主体(即subject)
-
ClusterRoleBinding:将集群角色绑定到主体
主体(subject)
-
User:用户
-
Group:用户组
-
ServiceAccount:服务账号
示例:为aliang用户授权default命名空间Pod读取权限
1、用K8S CA签发客户端证书
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
}
EOF
cat > aliang-csr.json <<EOF
{
"CN": "aliang",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -config=ca-config.json -profile=kubernetes aliang-csr.json | cfssljson -bare aliang
2、生成kubeconfig授权文件
生成kubeconfig授权文件:
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=https://192.168.31.61:6443 \
--kubeconfig=aliang.kubeconfig
# 设置客户端认证
kubectl config set-credentials aliang \
--client-key=aliang-key.pem \
--client-certificate=aliang.pem \
--embed-certs=true \
--kubeconfig=aliang.kubeconfig
# 设置默认上下文
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=aliang \
--kubeconfig=aliang.kubeconfig
# 设置当前使用配置
kubectl config use-context kubernetes --kubeconfig=aliang.kubeconfig
3、创建RBAC权限策略
创建角色(权限集合):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
将aliang用户绑定到角色:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: aliang
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
测试:
# kubectl --kubeconfig=aliang.kubeconfig get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-df88f57df-bv8h7 1/1 Running 0 8h
web-0 1/1 Running 0 7h25m
web-1 1/1 Running 0 7h25m
web-2 1/1 Running 0 7h25m
# kubectl --kubeconfig=aliang.kubeconfig get pods -n kube-system
Error from server (Forbidden): pods is forbidden: User "aliang" cannot list resource "pods" in API group "" in the namespace "kube-system"
aliang用户只有访问default命名空间Pod读取权限。
## 授权dashboard houbinglei 用户使用kubeconfig,只读权限。
## 创建sa
kubectl create serviceaccount houbinglei -n kube-system
##创建role
vi role.yaml
ikind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: kube-system
name: houbinglei
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
## rolebinding
vi bind.yaml
ikind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: role-bind-dashboard-admin2
namespace: kube-system
subjects:
- kind: ServiceAccount
name: houbinglei
namespace: kube-system
roleRef:
kind: Role
name: houbinglei
apiGroup: rbac.authorization.k8s.io
# 产生kubeconfig
DASH_TOCKEN=$(kubectl get secret -n kube-system houbinglei-token-pdfjb -o jsonpath={.data.token}|base64 -d)
kubectl config set-cluster kubernetes --server=10.0.0.200:6443 --kubeconfig=/root/houbinglei.conf
kubectl config set-credentials houbinglei --token=$DASH_TOCKEN --kubeconfig=/root/houbinglei.conf
kubectl config set-context houbinglei@kubernetes --cluster=kubernetes --user=houbinglei --kubeconfig=/root/houbinglei.conf
kubectl config use-context houbinglei@kubernetes --kubeconfig=/root/houbinglei.conf
1、安装编译环境
yum install java-1.8.0-openjdk maven -y
2、编译构建
mvn clean package -DskipTests=true
3、替换maven国内源
/etc/maven/settings.xml
<mirror>
<id>central</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
4、使用Dockerfile构建镜像并推送到镜像仓库
docker build -t 192.168.31.70/dev/java-demo:v10 .
docker login 192.168.31.70
docker push 192.168.31.70/dev/java-demo:v10
5、创建secret保存harbor认证信息
kubectl create secret docker-registry dockerpullauth --docker-username=admin --docker-password=Harbor12345 --docker-server=192.168.31.70
6、编写yaml部署(deployment、service、ingress)
7、创建数据库
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
mysql -uroot -p$MYSQL_ROOT_PASSWORD
mysql> grant all on test.* to wp@'%' identified by '123456';
更多推荐
所有评论(0)