k8s 部署应用
目录
一. 部署一个应用
二. 扩容或缩容
三. 节点污点
四. Pod 调度策略
1. request limits
2. 节点标签选择器
3. 节点亲和性
五. secret
1. secret 创建方式
a. 命令行创建
b.编写 yaml
2. secret资源的使用方式
a. 添加到 Pod 的环境变量
b. 以 volume 的形式挂载到 pod
六. ConfigMap
七. 存储编排
1. 本地存储
a. 创建 PV
b.创建 PVC
c. Pod 绑定 PVC
2. NFS 存储
八. 服务发现与负载均衡
看完ubuntu 搭建 k8s 集群后我们搭建起了一个 k8s 集群,继续学习 k8s,本文讲述在k8s中部署应用的相关操作.
kubectl 是 k8s 集群管理控制器,使用kubectl api-resources可以显示服务器支持的 API 资源
接下来进行实战
一. 部署一个应用
deployment 是 Pod 之上的抽象,他可以定义一组 Pod 的副本数目,以及这个 Pod 的版本.一般大家用 Deployment 来做应用真正的管理,而 Pod 是组成 Deployment 最小的单元
kubectl create deployment web --image=nginx:1.14 --dry-run -o yaml > web.yaml
create deployment web 创建一个名为 web 的 deployment 资源
--dry-run 表示检查语法,但不实际执行
-o yaml 表示以 yaml 格式输出
> web.yaml 表示输出重定向到 web.yaml
web.yaml
apiVersion: apps/v1 # 版本号
kind: Deployment # 种类,还有 Pod 之类的
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:1.14 # 指定的镜像文件
name: nginx
resources: {}
status: {}
用下面的命令将配置 web.yaml 应用到 resource,
kubectl apply -f web.yaml
执行完毕后可以通过以下命令查看 Deployment 和 Pod
kubectl get deplyment,pods -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.extensions/web 1/1 1 1 34m nginx nginx:1.14 app=web
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/web-7c5c4cb946-zxf97 1/1 Running 0 8s 10.24.1.11 k8s-node1
可以到当前资源正在正常运行,
curl 10.24.1.11
如果有 nginx 的标准返回说明应用已经部署完毕
二. 扩容或缩容
k8s 扩容十分简单,只需要修改之前的 web.yaml 文件,将 replicas的值改为 10,然后再更新配置
kubectl replace -f web.yaml
也可以直接使用 scale 命令,一键指定副本数
kubectl scale deploy web --replicas=10
三. 节点污点
节点的属性:
NoSchedult: 一定不被调度,master 默认为此
PreferNodSchedult: 尽量不被调度
NoExecute: 不会调度,并且还会驱逐 Node 已有 Pod
none: 正常调度
查看当前节点污点值
kubectl describe node k8s-master | grep Taints
节点删除污点
kubectl taint node k8s-master node-role.kubernetes.io/master:NoSchedule-
节点设置污点
kubectl taint node k8s-master node-role.kubernetes.io/master=:NoSchedule
四. Pod 调度策略
Pod 的调度策略会影响 Pod 最终被调度到哪些节点上:
预选策略 必须全部满足,比如 node 是否正常,对 pod 依赖的存储卷是否能满足需求
优选策略 会根据启用的函数的得分相加得到评估
高级调度
Toleration
Taint
label
Affinity 分为软亲和性和硬亲和性
- request limits
继续在之前的环境上测试
先删除之前部署的资源
kubectl delete deployment web
然后修改web.yaml的containers字段
containers:
- image: nginx:1.14
name: nginx
resources:
requests:
memory: “3Gi”
limits:
memory: “4Gi”
最后应用
kubectl apply -f web.yaml
2. 节点标签选择器
删除 deployment
kubectl delete deployment web
给节点打标签
kubectl label node k8s-master test23_env=prod
修改web.yaml的containers字段
spec:
hostNetwork: true
containers:
- image: nginx:1.14
name: nginx
resources: {}
nodeSelector:
test123_env: prod
可以发现 Pod 都被调度到了 master 节点,并且节点的污点值的优先级高于标签
删除标签
kubectl label node k8s-master test123_env-
3. 节点亲和性
亲和性和节点选择器类似, 多了操作符:In NotIn Eists Gt Lt DoesNotExists,
软亲和性 preferreDuringSchedulingIgnoredDuringExecution 非必须满足
硬亲和性
requiredDuringSchedulingIgnoredDuringExecution 必须满足
spec:
containers:
- image: nginx:1.14
name: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: test123_env
operator: In
values:
- dev
- test
preferreDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
- matchExpressions:
- key: group
operator: In
values:
- ttttest
五. secret
secret 是包含少量敏感数据(例如密码,令牌或密钥)的对象.不然此类细心就可能会放入 Pod 或容器镜像中.使用 secret 意外着不需要将应用程序代码中包含机密数据.
secret 可以独立于使用它们的 Pod 创建,因此在创建,查看和编辑 Pod 的工作流程中暴露 secret 的风险较小.
Secret 可以通过三种方式于 Pod 一起使用:
作为挂载在一个或多个容器上的卷中的文件
作为容器的环境变量
在为 Pod拉取镜像时有 kubelet 执行
- secret 创建方式
a. 命令行创建
创建名为secret1的 secret 资源
echo -n ‘admin’ > ./username
echo -n ‘123456789’ > ./password
kubectl create secret generic secret1 --from-file=./username --from-file=./password
b.编写 yaml
首先获取 user 和 password 的 base64 编码
echo -n ‘admin’ | base64
echo -n ‘123456789’ | base64
然后编写 yaml 文件
vim secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: secret2
type: Opaque
data:
username: YWRtaW4=
password: MTIzNDU2Nzg5
最后使用secret.yaml文件创建
kubectl apply -f secret.yaml
查看指定的 secret 资源信息
kubectl describe secret secret1
查看所有 secret 资源信息
kubectl get secret
查看指定 secret 资源的内容
kubectl get secret secret2 -o jsonpath=‘{.data}’
输出 map[password:MTIzNDU2Nzg5 username:YWRtaW4=]%
echo -n “MTIzNDU2Nzg5” | base64 --decode # 解码
删除创建的 secret 资源
kubectl delete secret secret1
2. secret资源的使用方式
a. 添加到 Pod 的环境变量
b. 以 volume 的形式挂载到 pod
六. ConfigMap
ConfigMap 和 secret 类似但是不需要加密
vim redis.map
redis.ip=127.0.0.1
redis.port=6379
redis.password=123456
执行下面的命令创建一个名为redis-config的 ConfigMap
kubectl create configmap redis-config --from-file=redis.map
七. 存储编排
自动挂载所选存储系统,包括本地存储,网络存储系统.
PV: PersistentVolume, 持久化卷, PV 是存储的抽象,为了使本地磁盘与网络磁盘提供一致的服务.
PVC: PersistentVolumnClaim, 持久化卷声明, PVC 是 PV 的使用者,当底层存储变化了,只需要修改 PV,而不用修改 Pod
- 本地存储
a. 创建 PV
创建一个 PV.yaml 声明的本地存储路径为/data/hostpath
vim PV.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
hostPath:
path: /data/hostpath
创建 PV 资源
kubectl apply -f PV.yaml
查看已有的 PV 资源
kubectl get pv
这个 pv 的状态为Available,说明还没有被 PVC 绑定,
⚠️注意这里声明的 hostPath 所有节点都有
b.创建 PVC
vim PVC.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: manual
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
创建 PVC 资源
kubectl apply -f PVC.yaml
查看
kubectl get pv,pvc
可以发现 pv 的状态变为了 Bound,表示这个 pv已经被绑定,PVC 是由 k8s 查找满足我们声明要求的 PV,然后由它来绑定的.
c. Pod 绑定 PVC
修改之前的 web.yaml的Containers字段
containers:
- image: nginx:1.14
name: nginx
volumeMounts:
- name: myresource
mountPath: /usr/share/nginx/html
volumes:
- name: myresource
persistentVolumeClaim:
claimName: my-pvc
⚠️注意在Pod 所在的 node 的/data/hostpath目录下创建 index.html,不然本地路径替换了原有的路径,里面内容为空.
将 web.yaml中的replica设置为多个后, PV 虽然只有一个.但是与 Pod 的概念类似,与它绑定的 Pod 有 N 个副本,PV就有 N 个副本,且PV 的副本之间的内容可以不一致
我尝试使用 hostNetwork: true,发现这样使得一台 node 只能启动一个 Pod.所以使用 StatefulSet+PV+hostNetwork 就可以部署类似挖矿的程序,
root @ k8s-master in ~ [10:07:19]
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-84fc5964b5-27hfv 1/1 Running 1 9m35s 192.168.1.21 k8s-master
web-84fc5964b5-j8w24 0/1 CrashLoopBackOff 5 4m51s 192.168.1.21 k8s-master
web-84fc5964b5-n8lzh 1/1 Running 0 9m34s 192.168.1.8 k8s-node1
root @ k8s-master in ~ [10:07:27]
$ curl 192.168.1.21
master hello world
root @ k8s-master in ~ [10:07:34]
$ curl 192.168.1.8
node1 hello world
-
NFS 存储
安装 NFS 服务器
安装nfs
yum install -y nfs-utils
创建共享目录
mkdir -p /data/nfs
配置共享目录
cat > /etc/exports <<EOF
/data/nfs *(rw,no_root_squash)
EOF
启动nfs服务
systemctl start nfs
查看服务是否启动成功
ps aux | grep nfs
修改 PV.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
labels:
type: remote
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs: # 声明nfs存储
path: /data/nfs
server: 192.168.108.100
apply 所有
八. 服务发现与负载均衡
扩容后有很多 Pod,访问每个 Pod 的方式都是不同的,如何均匀的访问每一个 Pod(负载均衡),并且当扩容或者缩容的时候能够动态的将Pod添加或者剔除出负载均衡的范围(服务发现).
service 类型介绍(http://dockone.io/article/4884)
k8s 中的 Service用来提供这个服务,service 有 3 种类型
ClusterIp, 集群内部访问(默认)
NodePort: 集群外部访问(包含 ClusterIp)
LoadBalancer: 暴露服务到 internet 的标准方式
Ingress: 它处于多个服务的前端,扮演着“智能路由”或者集群入口的角色。
kubectl expose deployment web --port=8080 --target-port=80 --type=NodePort --dry-run -o yaml > service.yaml
expose deployment web 将类型为 deployment 的 web公开为新的k8s服务,
--port: 指定集群内部访问的端口
--target-port: 指定容器本身的端口
--type 表明这个 service 的类型
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 80
selector:
app: web
type: NodePort
status:
loadBalancer: {}