k8s 部署应用

看完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   <none>           <none>

可以到当前资源正在正常运行,
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 分为软亲和性和硬亲和性

1. request limits

继续在之前的环境上测试
先删除之前部署的资源
kubectl delete deployment web
然后修改web.yamlcontainers字段

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.yamlcontainers字段

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 执行

1. 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

1. 本地存储

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.yamlContainers字段

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   <none>           <none>
web-84fc5964b5-j8w24   0/1     CrashLoopBackOff   5          4m51s   192.168.1.21   k8s-master   <none>           <none>
web-84fc5964b5-n8lzh   1/1     Running            0          9m34s   192.168.1.8    k8s-node1    <none>           <none>

# 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

2. 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: {}
posted @ 2022-04-20 17:27  哪吒young  阅读(195)  评论(0编辑  收藏  举报