YONGFEIUALL

izheyi.com


  • Home

  • Archives

  • Categories

  • Tags

  • About

  • Search

K8s:Dashboard

Posted on 2021-07-05 | In k8s |

kubernetes还开发了一个基于web的用户界面(Dashboard)。用户可以使用Dashboard部署容器化的应用,还可以监控应用的状态,执行故障排查以及管理kubernetes中各种资源。

部署

  1. 下载yaml

    1
    [root@master ~]# wget  https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
    --2021-10-18 10:40:54--  https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
    正在解析主机 raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.111.133, 185.199.110.133, ...
    正在连接 raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... 已连接。
    已发出 HTTP 请求,正在等待回应... 200 OK
    长度:7552 (7.4K) [text/plain]
    正在保存至: “recommended.yaml”
    
    100%[==============================================================================================================>] 7,552       2.14KB/s 用时 3.4s
  2. 配置并运行Dashboard

    1
    # 新增type: NodePort 和 nodePort:31443,以便能实现非本机访问
    kind: Service
    apiVersion: v1
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
      name: kubernetes-dashboard
      namespace: kubernetes-dashboard
    spec:
      type: NodePort
      ports:
        - port: 443
          targetPort: 8443
          nodePort: 31443
      selector:
        k8s-app: kubernetes-dashboard
    
    # 部署
    [root@master ~]# kubectl create -f recommended.yaml 
    namespace/kubernetes-dashboard created
    serviceaccount/kubernetes-dashboard created
    service/kubernetes-dashboard created
    secret/kubernetes-dashboard-certs created
    secret/kubernetes-dashboard-csrf created
    secret/kubernetes-dashboard-key-holder created
    configmap/kubernetes-dashboard-settings created
    role.rbac.authorization.k8s.io/kubernetes-dashboard created
    clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
    rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
    clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
    deployment.apps/kubernetes-dashboard created
    service/dashboard-metrics-scraper created
    deployment.apps/dashboard-metrics-scraper created
    
    # 查看
    [root@master ~]# kubectl get pod,svc -n kubernetes-dashboard
    NAME                                            READY   STATUS    RESTARTS   AGE
    pod/dashboard-metrics-scraper-c79c65bb7-spq7w   1/1     Running   0          88s
    pod/kubernetes-dashboard-56484d4c5-8v84c        1/1     Running   0          88s
    
    NAME                                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE
    service/dashboard-metrics-scraper   ClusterIP   10.96.123.22   <none>        8000/TCP        88s
    service/kubernetes-dashboard        NodePort    10.106.25.93   <none>        443:31443/TCP   88s
  3. 创建访问账户

    1
    # 创建账号
    [root@k8s-master01-1 ~]# kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
    
    # 授权
    [root@k8s-master01-1 ~]# kubectl create clusterrolebinding dashboard-admin-rb --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
    
    # 获取账号token
    [root@master ~]# kubectl get secrets -n kubernetes-dashboard | grep dashboard-admin
    dashboard-admin-token-k6pp4        kubernetes.io/service-account-token   3      32s
    [root@master ~]# kubectl describe secrets dashboard-admin-token-k6pp4 -n kubernetes-dashboard
    Name:         dashboard-admin-token-k6pp4
    Namespace:    kubernetes-dashboard
    Labels:       <none>
    Annotations:  kubernetes.io/service-account.name: dashboard-admin
                  kubernetes.io/service-account.uid: 29dc2734-490e-4b03-bdad-a2574ac8ef59
    
    Type:  kubernetes.io/service-account-token
    
    Data
    ====
    ca.crt:     1025 bytes
    namespace:  20 bytes
    token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InplRkxEdGNqbk1md0tyNnV1a0JHSy1OMml4Y2Q1a1g1QU5qMDRsdkZJTDgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4tazZwcDQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMjlkYzI3MzQtNDkwZS00YjAzLWJkYWQtYTI1NzRhYzhlZjU5Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmVybmV0ZXMtZGFzaGJvYXJkOmRhc2hib2FyZC1hZG1pbiJ9.afoxaaCkhTggDxuiP13yC_fyd6yTKyHdB_0eSMqBZxpHR4jGLJnaMXO4WlHY07yPuo9vWA5izEv6qwfhueZi2dFkgMxdQdGKKQXsv1_qpnh9LxztxseYVXV9BNc55XUS2LIZg1If94tMd_meECNm8dVNuJIQd_0IN_cEG0csZNYoYbbyYgBkKJNNxLhmRotpuQ1QDxsEWVnLI8lhHr_vcX99Szv2IAqq2jiUWcsFTzIpAaSESUF8F1DxfaaWIpw-Jq9GnQILXb_HpIuFHW2ijaUik5V57w-oUIq6nSrQCBpxaTyY_ehQHLUUm4D3Bx9uYBhqlaZBVIvYTui_S_Rs0w

验证

在登录页面上输入上面的token

登录成功

Dashboard的使用在此不做过多说明。

K8s:ConfigMap & Secret

Posted on 2021-07-01 | In k8s |
ConfigMap

ConfigMap 允许您将配置文件与镜像文件分离,以使容器化的应用程序具有可移植性。

你可以使用四种方式来使用 ConfigMap 配置 Pod 中的容器:

  1. 在容器命令和参数内
  2. 容器的环境变量
  3. 在只读卷里面添加一个文件,让应用来读取
  4. 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap

例子

  1. 创建configmap.yaml:

    1
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: game-config
      namespace: dev
    data:
      # 类属性键;每一个键都映射到一个简单的值
      player_initial_lives: "3"
      ui_properties_file_name: "user-interface.properties"
    
      # 类文件键
      game.properties: |
        enemy.types=aliens,monsters
        player.maximum-lives=5    
      user-interface.properties: |
        color.good=purple
        color.bad=yellow
        allow.textmode=true
    1
    [root@master ~]# kubectl create -f configmap.yaml
    configmap/game-config created
    
    [root@master ~]# kubectl describe cm game-config -n dev
    Name:         game-config
    Namespace:    dev
    Labels:       <none>
    Annotations:  <none>
    
    Data
    ====
    game.properties:
    ----
    enemy.types=aliens,monsters
    player.maximum-lives=5    
    
    player_initial_lives:
    ----
    3
    ui_properties_file_name:
    ----
    user-interface.properties
    user-interface.properties:
    ----
    color.good=purple
    color.bad=yellow
    allow.textmode=true    
    
    Events:  <none>
  2. 创建pod-configmap.yaml

    1
    apiVersion: v1
    kind: Pod
    metadata:
      name: configmap-game
      namespace: dev
    spec:
      containers:
        - name: game
          image: nginx:1.17.1
          command: ["sleep", "3600"]
          env:
            # 定义环境变量
            - name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
              valueFrom:
                configMapKeyRef:
                  name: game-config           # 这个值来自 ConfigMap
                  key: player_initial_lives # 需要取值的键
            - name: UI_PROPERTIES_FILE_NAME
              valueFrom:
                configMapKeyRef:
                  name: game-config
                  key: ui_properties_file_name
          volumeMounts:
          - name: config
            mountPath: "/config"
            readOnly: true
      volumes:
        # 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
        - name: config
          configMap:
            # 提供你想要挂载的 ConfigMap 的名字
            name: game-config

    如果 Pod 中有多个容器,则每个容器都需要自己的 volumeMounts 块,但针对 每个 ConfigMap,你只需要设置一个 spec.volumes 块。

    1
    [root@master ~]# kubectl create -f pod-configmap.yaml
    pod/configmap-game created
    [root@master ~]# kubectl get pod configmap-game -n dev
    NAME             READY   STATUS    RESTARTS   AGE
    configmap-game   1/1     Running   0          33s
    [root@master ~]# kubectl exec -it configmap-game -n dev /bin/sh
    # cd config
    # ls
    game.properties  player_initial_lives  ui_properties_file_name	user-interface.properties
    # cat user-interface.properties
    color.good=purple
    color.bad=yellow
    allow.textmode=true

    当卷中使用的 ConfigMap 被更新时,所投射的键最终也会被更新。 kubelet 组件会在每次周期性同步时检查所挂载的 ConfigMap 是否为最新。

    以环境变量方式使用的 ConfigMap 数据不会被自动更新。 更新这些数据需要重新启动 Pod。

Secret

Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。Secrets其用法是跟ConfigMap基本上是一致,区别不同是ConfigMap是明文,而Secrets是经过base64加密过的。

有几种不同的方式来创建 Secret:

  • 使用 kubectl 命令创建 Secret
  • 使用配置文件来创建 Secret
  • 使用 kustomize 来创建 Secret
配置文件创建
  1. 数据进行编码

    1
    [root@master ~]# echo -n 'admin' | base64
    YWRtaW4=
    [root@master ~]# echo -n '123456' | base64
    MTIzNDU2
  2. 创建secret.yaml

    1
    apiVersion: v1
    kind: Secret
    metadata:
      name: secret
      namespace: dev
    type: Opaque
    data:
      username: YWRtaW4=
      password: MTIzNDU2
    1
    [root@master ~]# kubectl create -f secret.yaml
    secret/secret created
    [root@master ~]# kubectl describe secret secret -n dev
    Name:         secret
    Namespace:    dev
    Labels:       <none>
    Annotations:  <none>
    
    Type:  Opaque
    
    Data
    ====
    password:  6 bytes
    username:  5 bytes
环境变量引用

创建secretenv.yaml

1
apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
  namespace: dev
spec:
  containers:
  - name: mycontainer
    image: nginx:1.17.1
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: secret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: secret
            key: password
  restartPolicy: Never
1
[root@master ~]# vi secretenv.yaml
[root@master ~]# kubectl create -f secretenv.yaml 
pod/secret-pod created
[root@master ~]# kubectl get pod secret-pod -n dev
NAME         READY   STATUS    RESTARTS   AGE
secret-pod   1/1     Running   0          4s
[root@master ~]# kubectl exec -it secret-pod -n dev /bin/sh
# echo $SECRET_USERNAME
admin
# echo $SECRET_PASSWORD
123456

K8s:数据存储

Posted on 2021-06-25 | In k8s |

在前面已经提到,容器的生命周期可能很短,会被频繁地创建和销毁。那么容器在销毁时,保存在容器中的数据也会被清除。为了持久化保存容器的数据,kubernetes引入了Volume的概念。

Volume是Pod中能够被多个容器访问的共享目录,它被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下,kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命容器不与Pod中单个容器的生命周期相关,当容器终止或者重启时,Volume中的数据也不会丢失。

基本存储

EmptyDir

一种临时存储,pod创建的时候会在node节点上为容器申请一个临时的目录,跟随容器的生命周期,如容器删除,emptyDir定义的临时存储空间也会随之删除,容器发生意外crash则不受影响,同时如果容器发生了迁移,其上的数据也会丢失,emptyDir一般用于测试,或者缓存场景。注意:一个容器崩溃了不会导致数据的丢失,因为容器的崩溃并不移除pod.

资源文件:

1
apiVersion: v1
kind: Pod
metadata:
  name: volume-emptydir
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - containerPort: 80
    volumeMounts:  # 将logs-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
    - name: logs-volume
      mountPath: /var/log/nginx
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始命令,动态读取指定文件中内容
    volumeMounts:  # 将logs-volume 挂在到busybox容器中,对应的目录为 /logs
    - name: logs-volume
      mountPath: /logs
  volumes: # 声明volume, name为logs-volume,类型为emptyDir
  - name: logs-volume
    emptyDir: {}
1
2
3
4
5
6
7
8
关于type的值的一点说明:
DirectoryOrCreate 目录存在就使用,不存在就先创建后使用
Directory 目录必须存在
FileOrCreate 文件存在就使用,不存在就先创建后使用
File 文件必须存在
Socket unix套接字必须存在
CharDevice 字符设备必须存在
BlockDevice 块设备必须存在
HostPath

HostPath就是将Node主机中一个实际目录挂在到Pod中,以供容器使用,这样的设计就可以保证Pod销毁了,但是数据依据可以存在于Node主机上。

NFS

NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node跟NFS的对接没问题,数据就可以成功访问。

PV与PVC

  • PV(Persistent Volume)是持久化卷的意思,是对底层的共享存储的一种抽象。一般情况下PV由kubernetes管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。
  • PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC其实就是用户向kubernetes系统发出的一种资源需求申请。
PV

PV是存储资源的抽象,下面是资源清单文件:

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1  
kind: PersistentVolume
metadata:
name: pv2
spec:
nfs: # 存储类型,与底层真正存储对应
capacity: # 存储能力,目前只支持存储空间的设置
storage: 2Gi
accessModes: # 访问模式
storageClassName: # 存储类别
persistentVolumeReclaimPolicy: # 回收策略

PV 的关键配置参数说明:

  • 存储类型

    底层实际存储的类型,kubernetes支持多种存储类型,每种存储类型的配置都有所差异

  • 存储能力(capacity)

    目前只支持存储空间的设置( storage=1Gi ),不过未来可能会加入IOPS、吞吐量等指标的配置

  • 访问模式(accessModes)

    用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

    • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
    • ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
    • ReadWriteMany(RWX):读写权限,可以被多个节点挂载
  • 回收策略(persistentVolumeReclaimPolicy)

    当PV不再被使用了之后,对其的处理方式。目前支持三种策略:

    • Retain (保留) 保留数据,需要管理员手工清理数据
    • Recycle(回收) 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
    • Delete (删除) 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务
  • 存储类别

    PV可以通过storageClassName参数指定一个存储类别

    • 具有特定类别的PV只能与请求了该类别的PVC进行绑定
    • 未设定类别的PV则只能与不请求任何类别的PVC进行绑定
  • 状态(status)

    一个 PV 的生命周期中,可能会处于4中不同的阶段:

    • Available(可用): 表示可用状态,还未被任何 PVC 绑定
    • Bound(已绑定): 表示 PV 已经被 PVC 绑定
    • Released(已释放): 表示 PVC 被删除,但是资源还未被集群重新声明
    • Failed(失败): 表示该 PV 的自动回收失败
PVC

PVC是资源的申请,用来声明对存储空间、访问模式、存储类别需求信息。下面是资源清单文件:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc
namespace: dev
spec:
accessModes: # 访问模式
selector: # 采用标签对PV选择
storageClassName: # 存储类别
resources: # 请求空间
requests:
storage: 5Gi

PVC 的关键配置参数说明:

  • 访问模式(accessModes)

    用于描述用户应用对存储资源的访问权限

  • 选择条件(selector)

    通过Label Selector的设置,可使PVC对于系统中己存在的PV进行筛选

  • 存储类别(storageClassName)

    PVC在定义时可以设定需要的后端存储的类别,只有设置了该class的pv才能被系统选出

  • 资源请求(Resources )

    描述对存储资源的请求

生命周期

PV和PVC之间的相互作用遵循这个生命周期:Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling

  • 资源供应:管理员手动创建底层存储和PV
  • 资源绑定:用户创建PVC,k8s负责根据PVC的声明去寻找PV,并绑定
  • 资源使用:用户可在pod中像volume一样使用pvc
  • 资源释放:用户删除pvc来释放pv
  • 资源回收:k8s根据pv设置的回收策略进行资源的回收
验证

k8s使用NFS共享存储有两种方式:

1.手动方式静态创建所需要的PV和PVC。
2.通过创建PVC动态地创建对应PV,无需手动创建PV。

K8s:Ingress

Posted on 2021-06-23 | In k8s |

介绍

k8s 对外暴露服务(service)主要有两种方式:NotePort, LoadBalance, 此外externalIPs也可以使各类service对外提供服务,但是当集群服务很多的时候,NodePort方式最大的缺点是会占用很多集群机器的端口;LB方式最大的缺点则是每个service一个LB又有点浪费和麻烦,并且需要k8s之外的支持; 而ingress则只需要一个NodePort或者一个LB就可以满足所有service对外服务的需求。

举个例子,现在集群有api、文件存储、前端3个service,可以通过一个ingress对象来实现图中的请求转发:

实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务。在这里有两个核心概念:

  • ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则
  • ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等

Ingress(以Nginx为例)的工作原理如下:

  1. 用户编写Ingress规则,说明哪个域名对应kubernetes集群中的哪个Service

  2. Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置

  3. Ingress控制器会将生成的Nginx配置写入到一个运行着的Nginx服务中,并动态更新

  4. 到此为止,其实真正在工作的就是一个Nginx了,内部配置了用户定义的请求转发规则

Ingress的使用

环境搭建
1
[root@master ~]# mkdir ingress
[root@master ~]# cd ingress

[root@master ingress]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
--2021-10-19 11:11:40--  https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
正在解析主机 raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.109.133, 185.199.111.133, ...
正在连接 raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:6635 (6.5K) [text/plain]
正在保存至: “mandatory.yaml”

[root@master ingress]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
--2021-10-19 11:11:55--  https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
正在解析主机 raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.109.133, 185.199.108.133, 185.199.110.133, ...
正在连接 raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:471 [text/plain]
正在保存至: “service-nodeport.yaml”

[root@master ingress]# ls
mandatory.yaml  service-nodeport.yaml
[root@master ingress]# kubectl apply -f ./
namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
limitrange/ingress-nginx created
service/ingress-nginx created

[root@master ingress]# kubectl get pod -n ingress-nginx
NAME                                        READY   STATUS              RESTARTS   AGE
nginx-ingress-controller-7f74f657bd-q5zwf   0/1     Running              0          16s
[root@master ingress]# kubectl get pod,svc -n ingress-nginx
NAME                                            READY   STATUS              RESTARTS   AGE
pod/nginx-ingress-controller-7f74f657bd-q5zwf   0/1     ContainerCreating   0          31s

NAME                    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
service/ingress-nginx   NodePort   10.106.103.131   <none>        80:32635/TCP,443:31777/TCP   31s
Service和Pod

创建tomcat-nginx.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80

---

apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: tomcat-pod
template:
metadata:
labels:
app: tomcat-pod
spec:
containers:
- name: tomcat
image: tomcat:8.5-jre10-slim
ports:
- containerPort: 8080

---

apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None
type: ClusterIP
ports:
- port: 80
targetPort: 80

---

apiVersion: v1
kind: Service
metadata:
name: tomcat-service
namespace: dev
spec:
selector:
app: tomcat-pod
clusterIP: None
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
1
[root@master ingress]# kubectl create -f tomcat-nginx.yaml
deployment.apps/nginx-deployment created
deployment.apps/tomcat-deployment created
service/nginx-service created
service/tomcat-service created

[root@master ingress]# kubectl get pod,svc -n dev
NAME                                     READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-6696798b78-4z9h9    1/1     Running   0          3m45s
pod/nginx-deployment-6696798b78-n2ff8    1/1     Running   0          3m45s
pod/nginx-deployment-6696798b78-xbnjh    1/1     Running   0          3m45s
pod/tomcat-deployment-58467d5474-4t275   1/1     Running   0          3m45s
pod/tomcat-deployment-58467d5474-c6cst   1/1     Running   0          3m45s
pod/tomcat-deployment-58467d5474-mrpww   1/1     Running   0          3m45s

NAME                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/nginx-service    ClusterIP   None             <none>        80/TCP         3m45s
service/tomcat-service   ClusterIP   None             <none>        8080/TCP       3m45s
HTTP代理

创建ingress-http.yaml

1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-http
  namespace: dev
spec:
  rules:
  - host: nginx.izheyi.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.izheyi.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080
1
[root@master ingress]# kubectl create -f ingress-http.yaml 
ingress.extensions/ingress-http created

[root@master ingress]# kubectl get ing ingress-http -n dev
NAME           HOSTS                                ADDRESS   PORTS   AGE
ingress-http   nginx.izheyi.com,tomcat.izheyi.com             80      5s

[root@master ingress]# kubectl describe ing ingress-http  -n dev
Name:             ingress-http
Namespace:        dev
Address:          
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host               Path  Backends
  ----               ----  --------
  nginx.izheyi.com   
                     /   nginx-service:80 (10.244.1.20:80,10.244.1.21:80,10.244.2.26:80)
  tomcat.izheyi.com  
                     /   tomcat-service:8080 (10.244.1.22:8080,10.244.2.24:8080,10.244.2.25:8080)
Annotations:
Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  CREATE  27s   nginx-ingress-controller  Ingress dev/ingress-http

增加Hosts

1
192.168.36.10 nginx.izheyi.com
192.168.36.10 tomcat.izheyi.com
1
[root@master ~]# kubectl get svc -n ingress-nginx
NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.106.103.131   <none>        80:32635/TCP,443:31777/TCP   124m

HTTPS代理
  1. 创建证书

    1
    # 生成证书
    [root@master ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=izhey.com"
    Generating a 2048 bit RSA private key
    ..........................................................+++
    ..................................................................................................................................+++
    writing new private key to 'tls.key'
    -----
    
    # 创建密钥
    [root@master ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
    secret/tls-secret created
  1. 创建ingress-https.yaml

    1
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: ingress-https
      namespace: dev
    spec:
      tls:
        - hosts:
          - nginx.itheima.com
          - tomcat.itheima.com
          secretName: tls-secret # 指定秘钥
      rules:
      - host: nginx.izheyi.com
        http:
          paths:
          - path: /
            backend:
              serviceName: nginx-service
              servicePort: 80
      - host: tomcat.izheyi.com
        http:
          paths:
          - path: /
            backend:
              serviceName: tomcat-service
              servicePort: 8080
    1
    [root@master ~]# kubectl create -f ingress-https.yaml
    ingress.extensions/ingress-https created
    [root@master ~]# kubectl get ing ingress-https -n dev
    NAME            HOSTS                                ADDRESS   PORTS     AGE
    ingress-https   nginx.izheyi.com,tomcat.izheyi.com             80, 443   11s
    [root@master ~]# kubectl describe ing ingress-https -n dev
    Name:             ingress-https
    Namespace:        dev
    Address:          10.106.103.131
    Default backend:  default-http-backend:80 (<none>)
    TLS:
      tls-secret terminates nginx.itheima.com,tomcat.itheima.com
    Rules:
      Host               Path  Backends
      ----               ----  --------
      nginx.izheyi.com   
                         /   nginx-service:80 (10.244.1.20:80,10.244.1.21:80,10.244.2.26:80)
      tomcat.izheyi.com  
                         /   tomcat-service:8080 (10.244.1.22:8080,10.244.2.24:8080,10.244.2.25:8080)
    Annotations:
    Events:
      Type    Reason  Age   From                      Message
      ----    ------  ----  ----                      -------
      Normal  CREATE  25s   nginx-ingress-controller  Ingress dev/ingress-https
      Normal  UPDATE  3s    nginx-ingress-controller  Ingress dev/ingress-https
    1
    [root@master ~]# kubectl get svc -n ingress-nginx
    NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx   NodePort   10.106.103.131   <none>        80:32635/TCP,443:31777/TCP   148m
  2. 用https://即可访问

    1
    https://nginx.izheyi.com:31777/
    
    https://tomcat.izheyi.com:31777/

K8s:Service

Posted on 2021-06-19 | In k8s |

在k8stes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。

为了解决这个问题,k8s提供了Service资源,Service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。

代理模式

Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则。

有三种代理模式

userspace和iptables不做解读,最常用的是ipvs模式。

Client Pod请求到达内核空间时,根据ipvs规则直接分发到各Pod上。kube-proxy会监视Kubernetes Service对象和Endpoints,调用netlink接口以相应的创建ipvs规则并定期与Kubernetes Service对象和Endpoints对象同步ipvs规则,以确保ipvs状态与期望一致。访问服务时,流量将被重定向到其中一个后端Pod。

此外,ipvs为负载均衡算法提供了更多选项,例如:

1
2
3
4
5
6
rr:轮询调度
lc:最小连接数
dh:目标哈希
sh:源哈希
sed:最短期望延迟
nq:不排队调度

Service类型

Service的资源清单文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kind: Service  # 资源类型
apiVersion: v1 # 资源版本
metadata: # 元数据
name: service # 资源名称
namespace: dev # 命名空间
spec: # 描述
selector: # 标签选择器,用于确定当前service代理哪些pod
app: nginx
type: # Service类型,指定service的访问方式
clusterIP: # 虚拟服务的ip地址
sessionAffinity: # session亲和性,支持ClientIP、None两个选项
ports: # 端口信息
- protocol: TCP
port: 3017 # service端口
targetPort: 5003 # pod端口
nodePort: 31122 # 主机端口
  • ClusterIP:默认值,它是Kubernetes系统自动分配的虚拟IP,只能在集群内部访问
  • NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务
  • LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持
  • ExternalName: 把集群外部的服务引入集群内部,直接使用

Endpoints & Headless

  • Endpoints

    Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址,它是根据service配置文件中selector描述产生的。

    一个Service由一组Pod组成,这些Pod通过Endpoints暴露出来,Endpoints是实现实际服务的端点集合。换句话说,service和pod之间的联系是通过endpoints实现的。

  • Headless

    在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,如果想要访问service,只能通过service的域名进行查询。

K8s:Pod控制器

Posted on 2021-06-10 | In k8s |

Pod控制器是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试进行重启,当根据重启策略无效,则会重新新建pod的资源。分为以下几类:

  • ReplicaSet:保证副本数量一直维持在期望值,并支持pod数量扩缩容,镜像版本升级
  • Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本
  • Horizontal Pod Autoscaler:可以根据集群负载自动水平调整Pod的数量,实现削峰填谷
  • DaemonSet:在集群中的指定Node上运行且仅运行一个副本,一般用于守护进程类的任务
  • Job:它创建出来的pod只要完成任务就立即退出,不需要重启或重建,用于执行一次性任务
  • Cronjob:它创建的Pod负责周期性任务控制,不需要持续后台运行
  • StatefulSet:管理有状态应用,作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序,StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计)。

ReplicaSet

ReplicaSet的主要作用是保证一定数量的pod正常运行,它会持续监听这些Pod的运行状态,一旦Pod发生故障,就会重启或重建。同时它还支持对pod数量的扩缩容和镜像版本的升降级。

ReplicaSet的资源清单文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: rs
spec: # 详情描述
replicas: 3 # 副本数量
selector: # 选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80

需要新了解的配置项就是spec下面几个选项:

  • replicas:指定副本数量,其实就是当前rs创建出来的pod的数量,默认为1

  • selector:选择器,它的作用是建立pod控制器和pod之间的关联关系,采用的Label Selector机制

    在pod模板上定义label,在控制器上定义选择器,就可以表明当前控制器能管理哪些pod了

  • template:模板,就是当前控制器创建pod所使用的模板板

创建pc-replicaset.yaml文件:

1
apiVersion: apps/v1
kind: ReplicaSet   
metadata:
  name: pc-replicaset
  namespace: dev
spec:
  replicas: 3
  selector: 
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建
[root@master ~]# kubectl create -f pc-replicaset.yaml
replicaset.apps/pc-replicaset created

# 查看rs
[root@master ~]# kubectl get rs pc-replicaset -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
pc-replicaset 3 3 3 22s nginx nginx:1.17.1 app=nginx-pod

# 查看当前控制器创建出来的pod
[root@master ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
pc-replicaset-6vmvt 1/1 Running 0 54s
pc-replicaset-fmb8f 1/1 Running 0 54s
pc-replicaset-snrk2 1/1 Running 0 54s

两种方式实现扩缩容

1
# 编辑rs的副本数量,修改spec:replicas: 6即可
[root@master ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited

# 当然也可以直接使用命令实现
# 使用scale命令, 后面--replicas=n直接指定目标数量即可
[root@master ~]# kubectl scale rs pc-replicaset --replicas=2 -n dev
replicaset.apps/pc-replicaset scaled

Deployment

这种控制器并不直接管理pod,而是通过管理ReplicaSet来简介管理Pod

在创建一个Deployment时,会自动创建一个ReplicaSet,然后由ReplicaSet去创建POD。在Deployment升级时,旧的ReplicaSet会保留,但pod都会升级到新的ReplicaSet上。

Deployment的资源清单文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
name: # rs名称
namespace: # 所属命名空间
labels: #标签
controller: deploy
spec: # 详情描述
replicas: 3 # 副本数量
revisionHistoryLimit: 3 # 保留历史版本
paused: false # 暂停部署,默认是false
progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600
strategy: # 策略
type: RollingUpdate # 滚动更新策略
rollingUpdate: # 滚动更新
maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数
maxUnavailable: 30% # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数
selector: # 选择器,通过它指定该控制器管理哪些pod
matchLabels: # Labels匹配规则
app: nginx-pod
matchExpressions: # Expressions匹配规则
- {key: app, operator: In, values: [nginx-pod]}
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
创建

创建pc-deployment.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: dev
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
1
[root@master ~]# kubectl create -f pc-deployment.yaml 
deployment.apps/nginx-deployment created
[root@master ~]# kubectl get deploy nginx-deployment -n dev
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           8s
[root@master ~]# kubectl get pod -n dev
NAME                                READY   STATUS             RESTARTS   AGE
nginx-deployment-68ddf649b8-cnf8q   1/1     Running            0          25s
nginx-deployment-68ddf649b8-dtwbc   1/1     Running            0          25s
nginx-deployment-68ddf649b8-xwsqs   1/1     Running            0          26s
扩容
1
# 变更副本数量为5个
[root@master ~]# kubectl scale deploy nginx-deployment --replicas=5  -n dev
deployment.apps/nginx-deployment scaled

#查看
[root@master ~]# kubectl get pod -n dev
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-68ddf649b8-bq8n2   1/1     Running   0          5s
nginx-deployment-68ddf649b8-cnf8q   1/1     Running   0          24m
nginx-deployment-68ddf649b8-dtwbc   1/1     Running   0          24m
nginx-deployment-68ddf649b8-sspml   1/1     Running   0          4s
nginx-deployment-68ddf649b8-xwsqs   1/1     Running   0          24m

# 直接修改yaml文件,修改spec:replicas: 4即可
[root@master ~]# kubectl edit deploy pc-deployment -n dev
deployment.apps/pc-deployment edited
镜像更新
  • 通过set 命令直接修改image的版本进行升级:kubectl set image deployment/nginx-deployment nginx=nginx:1.17.2
  • 使用 kubectl edit deployment nginx-deployment 来修改image的值。

deployment支持两种更新策略:重建更新和滚动更新,可以通过strategy指定策略类型,支持两个属性:

1
2
3
4
5
6
7
strategy:指定新的Pod替换旧的Pod的策略, 支持两个属性:
type:指定策略类型,支持两种策略
Recreate:在创建出新的Pod之前会先杀掉所有已存在的Pod
RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本Pod
rollingUpdate:当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性:
maxUnavailable:用来指定在升级过程中不可用Pod的最大数量,默认为25%。
maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
  • Recreate这种方式通常不用
1
# 变更镜像
[root@master ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n dev
deployment.apps/pc-deployment image updated

# 观察升级过程
[root@master ~]#  kubectl get pods -n dev -w
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-65qcw   1/1     Running   0          31s
pc-deployment-5d89bdfbf9-w5nzv   1/1     Running   0          31s
pc-deployment-5d89bdfbf9-xpt7w   1/1     Running   0          31s

pc-deployment-5d89bdfbf9-xpt7w   1/1     Terminating   0          41s
pc-deployment-5d89bdfbf9-65qcw   1/1     Terminating   0          41s
pc-deployment-5d89bdfbf9-w5nzv   1/1     Terminating   0          41s

pc-deployment-675d469f8b-grn8z   0/1     Pending       0          0s
pc-deployment-675d469f8b-hbl4v   0/1     Pending       0          0s
pc-deployment-675d469f8b-67nz2   0/1     Pending       0          0s

pc-deployment-675d469f8b-grn8z   0/1     ContainerCreating   0          0s
pc-deployment-675d469f8b-hbl4v   0/1     ContainerCreating   0          0s
pc-deployment-675d469f8b-67nz2   0/1     ContainerCreating   0          0s

pc-deployment-675d469f8b-grn8z   1/1     Running             0          1s
pc-deployment-675d469f8b-67nz2   1/1     Running             0          1s
pc-deployment-675d469f8b-hbl4v   1/1     Running             0          2s
  • rollingUpdate
1
# 变更镜像
[root@master ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.3 -n dev 
deployment.apps/pc-deployment image updated

# 观察升级过程
[root@master ~]# kubectl get pods -n dev -w
NAME                           READY   STATUS    RESTARTS   AGE
pc-deployment-c848d767-8rbzt   1/1     Running   0          31m
pc-deployment-c848d767-h4p68   1/1     Running   0          31m
pc-deployment-c848d767-hlmz4   1/1     Running   0          31m
pc-deployment-c848d767-rrqcn   1/1     Running   0          31m

pc-deployment-966bf7f44-226rx   0/1     Pending             0          0s
pc-deployment-966bf7f44-226rx   0/1     ContainerCreating   0          0s
pc-deployment-966bf7f44-226rx   1/1     Running             0          1s
pc-deployment-c848d767-h4p68    0/1     Terminating         0          34m

pc-deployment-966bf7f44-cnd44   0/1     Pending             0          0s
pc-deployment-966bf7f44-cnd44   0/1     ContainerCreating   0          0s
pc-deployment-966bf7f44-cnd44   1/1     Running             0          2s
pc-deployment-c848d767-hlmz4    0/1     Terminating         0          34m

pc-deployment-966bf7f44-px48p   0/1     Pending             0          0s
pc-deployment-966bf7f44-px48p   0/1     ContainerCreating   0          0s
pc-deployment-966bf7f44-px48p   1/1     Running             0          0s
pc-deployment-c848d767-8rbzt    0/1     Terminating         0          34m

pc-deployment-966bf7f44-dkmqp   0/1     Pending             0          0s
pc-deployment-966bf7f44-dkmqp   0/1     ContainerCreating   0          0s
pc-deployment-966bf7f44-dkmqp   1/1     Running             0          2s
pc-deployment-c848d767-rrqcn    0/1     Terminating         0          34m
版本Rollback

deployment支持版本升级过程中的暂停、继续功能以及版本回退等诸多功能,创建deployment时要增加–record参数,才能看到revision的变化。

kubectl rollout: 版本升级相关功能,支持下面的选项:

  • status 显示当前升级状态
  • history 显示 升级历史记录
  • pause 暂停版本升级过程
  • resume 继续已经暂停的版本升级过程
  • restart 重启版本升级过程
  • undo 回滚到上一级版本(可以使用–to-revision回滚到指定版本)

Horizontal Pod Autoscaler(HPA)

HPA可以获取每个Pod利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。

环境部署
  1. 安装metrics-server

    metrics-server可以用来收集集群中的资源使用情况

    1
    # 安装git
    [root@master ~]# yum install git -y
    
    # 获取metrics-server
    [root@master ~]# git clone -b v0.3.6 https://github.com/kubernetes-incubator/metrics-server
    # 修改deployment, 注意修改的是镜像和初始化参数
    [root@master ~]# cd /root/metrics-server/deploy/1.8+/
    [root@master 1.8+]# vim metrics-server-deployment.yaml
    metadata:
      name: metrics-server
      namespace: kube-system
      labels:
        k8s-app: metrics-server
    spec:
      selector:
        matchLabels:
          k8s-app: metrics-server
      template:
        metadata:
          name: metrics-server
          labels:
            k8s-app: metrics-server
        spec:
          hostNetwork: true
          serviceAccountName: metrics-server
          volumes:
          # mount in tmp so we can safely use from-scratch images and/or read-only containers
          - name: tmp-dir
            emptyDir: {}
          containers:
          - name: metrics-server
            image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
            imagePullPolicy: Always
            args:
            - --kubelet-insecure-tls
            - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
            volumeMounts:
            - name: tmp-dir
              mountPath: /tmp
    
    # 安装metrics-server
    [root@master 1.8+]# kubectl apply -f ./
    
    # 验证
    [root@master ~]# kubectl top node
    NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%     
    node1    144m         7%     377Mi           21%         
    node2    186m         9%     351Mi           18%
  2. deployment和servie

    1
    # 创建deployment
    [root@master ~]# kubectl run nginx --image=nginx:1.17.1 --requests=cpu=100m -n dev
    deployment.apps/nginx created
    
    # 创建service
    [root@master ~]# kubectl expose deploy nginx  --port=80 --target-port=80  --type=NodePort -n dev
    service/nginx exposed
    
    # 查看
    [root@master ~]# kubectl get deployment,pod,svc -n dev
    NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/nginx   1/1     1            1           47s
    
    NAME                         READY   STATUS    RESTARTS   AGE
    pod/nginx-7df9756ccc-bh8dr   1/1     Running   0          47s
    
    NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/nginx   NodePort   10.101.18.29   <none>        80:31830/TCP   35s

    创建pc-hpa.yaml文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    apiVersion: autoscaling/v1
    kind: HorizontalPodAutoscaler
    metadata:
    name: pc-hpa
    namespace: dev
    spec:
    minReplicas: 1 #最小pod数量
    maxReplicas: 10 #最大pod数量
    targetCPUUtilizationPercentage: 3 # CPU使用率指标
    scaleTargetRef: # 指定要控制的nginx信息
    apiVersion: /v1
    kind: Deployment
    name: nginx
    1
    # 创建hpa
    [root@master ~]# kubectl create -f pc-hpa.yaml
    horizontalpodautoscaler.autoscaling/pc-hpa created
    
    # 查看hpa
    [root@master ~]# kubectl get hpa -n dev
    NAME     REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
    pc-hpa   Deployment/nginx   0%/3%     1         10        1          62s
验证

对http://192.168.36.10:30668/压测,查看变化

1
[root@k8s-master01 ~]# kubectl get hpa -n dev -w
NAME   REFERENCE      TARGETS  MINPODS  MAXPODS  REPLICAS  AGE
pc-hpa  Deployment/nginx  0%/3%   1     10     1      4m11s
pc-hpa  Deployment/nginx  0%/3%   1     10     1      5m19s
pc-hpa  Deployment/nginx  22%/3%   1     10     1      6m50s
pc-hpa  Deployment/nginx  22%/3%   1     10     4      7m5s
pc-hpa  Deployment/nginx  22%/3%   1     10     8      7m21s
pc-hpa  Deployment/nginx  6%/3%   1     10     8      7m51s
pc-hpa  Deployment/nginx  0%/3%   1     10     8      9m6s
pc-hpa  Deployment/nginx  0%/3%   1     10     8      13m
pc-hpa  Deployment/nginx  0%/3%   1     10     1      14m

剩下的控制器不做过多学习验证,用到的时候可以直接官方文档。

K8s:Pod相关知识

Posted on 2021-06-06 | In k8s |

Pod 是 Kubernetes 的一个最小调度以及资源单元。用户可以通过 Kubernetes 的 Pod API 生产一个 Pod,让 Kubernetes 对这个 Pod 进行调度,也就是把它放在某一个 Kubernetes 管理的节点上运行起来。

Pods内运行一个或者多个container,container之间共享pod的网络ip资源,存储volume资源,计算等资源,方便pod内部的container之间能够实现快速的访问和交互。

Pod简单操作

kubernetes交互的方式通常分为四种:

  • 命令行,kubectl和kubernetes交互,完成资源的管理,命令行入门简单,但只能支持部分资源创建
  • API,通过resfulAPI以http的方式和kubernetes交互,适用于基于API做二次开发
  • SDK,提供各种语言原生的SDK,实现各种语言编程接入
  • YAML,通过易于理解的YAML文件格式,描述资源的定义,功能最丰富,最终转换为json格式

kubernetes中通过定义生申明式的方式定义资源,即通过在yaml文件中定义所需的资源,kubernetes通过controller-manager按照yaml文件中定义的资源去生成所需的资源。通常在kubernetes中通过yaml文件的方式定义资源,然后通过kubectl create -f 文件.yaml的方式应用配置。

Pod资源清单

1
apiVersion: v1     #必选,版本号,例如v1
kind: Pod         #必选,资源类型,例如 Pod
metadata:         #必选,元数据
  name: string     #必选,Pod名称
  namespace: string  #Pod所属的命名空间,默认为"default"
  labels:           #自定义标签列表
    - name: string                 
spec:  #必选,Pod中容器的详细定义
  containers:  #必选,Pod中容器列表
  - name: string   #必选,容器名称
    image: string  #必选,容器的镜像名称
    imagePullPolicy: [ Always|Never|IfNotPresent ]  #获取镜像的策略 
    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 #内存请求,容器启动的初始可用数量
    lifecycle: #生命周期钩子
        postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
        preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
    livenessProbe:  #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
      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的重启策略
  nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
  nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
  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的存储卷,挂载集群与定义的secret对象到容器内部
      scretname: string  
      items:     
      - key: string
        path: string
    configMap:         #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
      name: string
      items:
      - key: string
        path: string

这么多东西都记住不太可能,可以通过kubectl explain查到每个字段的含义,使用说明和使用方式。

1
[rootmaster ~]# kubectl explain pod
KIND:     Pod
VERSION:  v1
FIELDS:
   apiVersion   <string>
   kind <string>
   metadata     <Object>
   spec <Object>
   status       <Object>

[root@master ~]# kubectl explain pod.metadata
创建Pod

创建 pod-basic.yaml文件

1
apiVersion: v1
kind: Pod
metadata:
  name: pod-basic
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: # 设置容器暴露的端口列表
    - name: nginx-port
      containerPort: 80
      protocol: TCP
    imagePullPolicy: Never # 用于设置镜像拉取策略
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]

上面定义了一个比较简单Pod的配置,里面有两个容器。

imagePullPolicy,用于设置镜像拉取策略,kubernetes支持配置三种拉取策略:

  • Always:总是从远程仓库拉取镜像(一直远程下载)

  • IfNotPresent:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像(本地有就本地 本地没远程下载)

  • Never:只使用本地镜像,从不去远程仓库拉取,本地没有就报错 (一直使用本地)

    如果镜像tag为具体版本号, 默认策略是:IfNotPresent

    如果镜像tag为:latest(最终版本) ,默认策略是always

1
[root@master ~]# kubectl create ns dev
namespace/dev created
[root@master ~]# kubectl create -f pod-basic.yaml 
Error from server (Forbidden): error when creating "pod-basic.yaml": pods "pod-basic" is forbidden: error looking up service account dev/default: serviceaccount "default" not found
# 修理 Error
[root@master ~]# mkdir -p $HOME/.kube
[root@master ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
cp:是否覆盖"/root/.kube/config"? y
[root@master ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config

[root@master ~]# kubectl create -f pod-basic.yaml 
pod/pod-basic created
查看Pod
1
# 查看Pod状态
[root@master ~]# kubectl get pod -n dev
NAME        READY   STATUS    RESTARTS   AGE
pod-basic   2/2     Running   0          6m21s

# 查看Pod详细信息
[root@master ~]# kubectl describe pod pod-basic -n dev
Name:         pod-basic
Namespace:    dev
Priority:     0
Node:         node1/192.168.36.11
Start Time:   Fri, 15 Oct 2021 10:03:02 +0800
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           10.244.2.5
IPs:
  IP:  10.244.2.5
Containers:
  nginx:
    Container ID:   docker://7898e9c6351803089656d74defbf979f7126b1c01a370499c27cd882658ecaec
    Image:          nginx:1.17.1
    Image ID:       docker-pullable://nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbb
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Fri, 15 Oct 2021 10:03:48 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-5kcqv (ro)
  busybox:
    Container ID:  docker://99731cc93e57c7a5551f32f672cdd0f8c69f2f5af59e39f8203bbf8b40de2034
    Image:         busybox:1.30
    Image ID:      docker-pullable://busybox@sha256:4b6ad3a68d34da29bf7c8ccb5d355ba8b4babcad1f99798204e7abb43e54ee3d
    Port:          <none>
    Host Port:     <none>
    Command:
      /bin/sh
      -c
      touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;
    State:          Running
      Started:      Fri, 15 Oct 2021 10:03:48 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-5kcqv (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-5kcqv:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-5kcqv
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned dev/pod-basic to node1
  Normal  Pulling    3m14s      kubelet, node1     Pulling image "nginx:1.17.1"
  Normal  Pulled     2m30s      kubelet, node1     Successfully pulled image "nginx:1.17.1"
  Normal  Created    2m30s      kubelet, node1     Created container nginx
  Normal  Started    2m29s      kubelet, node1     Started container nginx
  Normal  Pulled     2m29s      kubelet, node1     Container image "busybox:1.30" already present on machine
  Normal  Created    2m29s      kubelet, node1     Created container busybox
  Normal  Started    2m29s      kubelet, node1     Started container busybox
进入Pod

kubectl exec pod名称 -n 命名空间 -it -c 容器名称 command使用这个命令就可以进入某个容器的内部,然后进行相关操作了

1
[root@master ~]# kubectl exec pod-basic -n dev -it -c busybox /bin/sh
/ # tail -f /tmp/hello.txt 
02:12:46
02:12:49
02:12:52
资源配额

容器中的程序要运行,肯定是要占用一定资源的,比如cpu和内存等,如果不对某个容器的资源做限制,那么它就可能吃掉大量资源,导致其它容器无法运行。针对这种情况,kubernetes提供了对内存和cpu的资源进行配额的机制,这种机制主要通过resources选项实现,他有两个子选项:

  • limits:用于限制运行时容器的最大占用资源,当容器占用资源超过limits时会被终止,并进行重启
  • requests :用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动

可以通过上面两个选项设置资源的上下限。

创建pod-resources.yaml

1
apiVersion: v1
kind: Pod
metadata:
  name: pod-resources
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    resources: # 资源配额
      limits:  # 限制资源(上限)
        cpu: "2" # CPU限制,单位是core数
        memory: "10Gi" # 内存限制
      requests: # 请求资源(下限)
        cpu: "1"  # CPU限制,单位是core数
        memory: "10Mi"  # 内存限制
  • cpu:core数,可以为整数或小数
  • memory: 内存大小,可以使用Gi、Mi、G、M等形式
1
# 运行Pod
[root@master ~]# kubectl create  -f pod-resources.yaml
pod/pod-resources created

# 查看发现pod运行正常
[root@master ~]# kubectl get pod pod-resources -n dev
NAME            READY   STATUS    RESTARTS   AGE  
pod-resources   1/1     Running   0          39s   

# 接下来,停止Pod
[root@master ~]# kubectl delete  -f pod-resources.yaml
pod "pod-resources" deleted

# 编辑pod,修改resources.requests.memory的值为10Gi
[root@master ~]# vim pod-resources.yaml

# 再次启动pod
[root@master ~]# kubectl create  -f pod-resources.yaml
pod/pod-resources created

# 查看Pod状态,发现Pod启动失败
[root@master ~]# kubectl get pod pod-resources -n dev -o wide
NAME            READY   STATUS    RESTARTS   AGE          
pod-resources   0/1     Pending   0          20s    

# 查看pod详情会发现,如下提示
[root@master ~]# kubectl describe pod pod-resources -n dev
Events:
  Type     Reason            Age        From               Message
  ----     ------            ----       ----               -------
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 3 Insufficient memory.

Pod生命周期

  • 运行初始化容器(init container)过程
  • 运行主容器(main container)
    • 容器启动后钩子(post start)、容器终止前钩子(pre stop)
    • 容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
Pod状态

在整个生命周期中,Pod会出现5种状态

  • 挂起(Pending):apiserver已经创建了pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
  • 运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
  • 成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
  • 失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
  • 未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致
Pod的创建过程

①用户通过kubectl或其他API客户端提交Pod Spec给API Server。

②API Server尝试将Pod对象的相关信息存储到etcd中,等待写入操作完成,API Server返回确认信息到客户端。

③API Server开始反映etcd中的状态变化。

④所有的Kubernetes组件通过”watch”机制跟踪检查API Server上的相关信息变动。

⑤kube-scheduler(调度器)通过其”watcher”检测到API Server创建了新的Pod对象但是没有绑定到任何工作节点。

⑥kube-scheduler为Pod对象挑选一个工作节点并将结果信息更新到API Server。

⑦调度结果新消息由API Server更新到etcd,并且API Server也开始反馈该Pod对象的调度结果。

⑧Pod被调度到目标工作节点上的kubelet尝试在当前节点上调用docker engine进行启动容器,并将容器的状态结果返回到API Server。

⑨API Server将Pod信息存储到etcd系统中。

⑩在etcd确认写入操作完成,API Server将确认信息发送到相关的kubelet。

初始化容器

初始化容器是在pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:

  1. 初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成
  2. 初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行
Webhook

kubernetes在主容器的启动之后和停止之前提供了两个钩子函数:

  • post start:容器创建之后执行,如果失败了会重启容器
  • pre stop :容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作

钩子处理器支持使用下面三种方式定义动作:

钩子处理器支持使用下面三种方式定义动作:

  • Exec命令:在容器内执行一次命令

    1
    lifecycle:
      postStart: 
        exec:
          command:
          - cat
          - /tmp/healthy
  • TCPSocket:在当前容器尝试访问指定的socket

    1
    2
    3
    4
    lifecycle:
    postStart:
    tcpSocket:
    port: 8080
  • HTTPGet:在当前容器中向某url发起http请求

    1
    2
    3
    4
    5
    6
    7
    lifecycle:
    postStart:
    httpGet:
    path: / #URI地址
    port: 80 #端口号
    host: 192.168.5.3 #主机地址
    scheme: HTTP #支持的协议,http或者https

创建pod-hook-exec.yaml文件

1
apiVersion: v1
kind: Pod
metadata:
  name: pod-hook-exec
  namespace: dev
spec:
  containers:
  - name: main-container
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    lifecycle:
      postStart: 
        exec: # 在容器启动的时候执行一个命令,修改掉nginx的默认首页内容
          command: ["/bin/sh", "-c", "echo postStart... > /usr/share/nginx/html/index.html"]
      preStop:
        exec: # 在容器停止之前停止nginx服务
          command: ["/usr/sbin/nginx","-s","quit"]
1
[root@master ~]# vim pod-hook-exec.yaml
[root@master ~]# kubectl create -f pod-hook-exec.yaml 
pod/pod-hook-exec created
[root@master ~]# kubectl get pods  pod-hook-exec -n dev -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
pod-hook-exec   1/1     Running   0          28s   10.244.2.7   node1   <none>           <none>
[root@master ~]# curl 10.244.2.7
postStart...
容器探测

容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例” 摘除 “,不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:

  • liveness probes:存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器
  • readiness probes:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量

livenessProbe 决定是否重启容器,readinessProbe 决定是否将请求转发给容器。

上面两种探针目前均支持三种探测方式:

  • Exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常
  • TCPSocket:将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常
  • HTTPGet:调用容器内Web应用的URL,如果返回的状态码在200和399之间,则认为程序正常,否则不正常

创建pod-liveness-tcpsocket.yaml

1
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-tcpsocket
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      tcpSocket:
        port: 8080 # 尝试访问8080端口
1
[root@master ~]# vi pod-liveness-tcpsocket.yaml
[root@master ~]# kubectl create -f pod-liveness-tcpsocket.yaml 
pod/pod-liveness-tcpsocket created

# 查看Pod详情
[root@master ~]# kubectl describe pods pod-liveness-tcpsocket -n dev
Events:
  Type     Reason     Age        From               Message
  ----     ------     ----       ----               -------
  Normal   Scheduled  <unknown>  default-scheduler  Successfully assigned dev/pod-liveness-tcpsocket to node1
  Normal   Pulled     14s        kubelet, node1     Container image "nginx:1.17.1" already present on machine
  Normal   Created    14s        kubelet, node1     Created container nginx
  Normal   Started    13s        kubelet, node1     Started container nginx
  Warning  Unhealthy  7s         kubelet, node1     Liveness probe failed: dial tcp 10.244.2.8:8080: connect: connection refused

# 稍等一会之后,再观察pod信息,就可以看到RESTARTS不再是0,而是一直增长
[root@master ~]# kubectl get pods pod-liveness-tcpsocket  -n dev
NAME                     READY   STATUS    RESTARTS   AGE
pod-liveness-tcpsocket   1/1     Running   3          2m50s
重启策略

一旦容器探测出现了问题,kubernetes就会对容器所在的Pod进行重启,其实这是由pod的重启策略决定的,pod的重启策略有 3 种,分别如下:

  • Always :容器失效时,自动重启该容器,这也是默认值。
  • OnFailure : 容器终止运行且退出码不为0时重启
  • Never : 不论状态为何,都不重启该容器

重启策略适用于pod对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作的延迟时长以此为10s、20s、40s、80s、160s和300s,300s是最大延迟时长。

创建pod-restartpolicy.yaml

1
apiVersion: v1
kind: Pod
metadata:
  name: pod-restartpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:
        scheme: HTTP
        port: 80
        path: /hello
  restartPolicy: Never # 设置重启策略为Never
1
[root@master ~]# kubectl create -f pod-restartpolicy.yaml
pod/pod-restartpolicy created

# 查看Pod详情
[root@master ~]# kubectl  describe pods pod-restartpolicy  -n dev
......
  Warning  Unhealthy  15s (x3 over 35s)  kubelet, node1     Liveness probe failed: HTTP probe failed with statuscode: 404
  Normal   Killing    15s                kubelet, node1     Container nginx failed liveness probe
  
# 多等一会,再观察pod的重启次数,发现一直是0,并未重启   
[root@master ~]# kubectl  get pods pod-restartpolicy -n dev
NAME                   READY   STATUS    RESTARTS   AGE
pod-restartpolicy      0/1     Running   0          5min42s

Pod调度

在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。但是在实际使用中,这并不满足的需求,因为很多情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这就要求了解kubernetes对Pod的调度规则,kubernetes提供了四大类调度方式:

  • 自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出
  • 定向调度:NodeName、NodeSelector
  • 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
  • 污点(容忍)调度:Taints、Toleration
定向调度

定向调度,指的是利用在pod上声明nodeName或者nodeSelector,以此将Pod调度到期望的node节点上。注意,这里的调度是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过pod运行失败而已。

  • nodeName调度

    NodeName用于强制约束将Pod调度到指定的Name的Node节点上。

    1
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-nodename
      namespace: dev
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
      nodeName: node1 # 指定调度到node1节点上
  • nodeSelector调度

    NodeSelector用于将pod调度到添加了指定标签的node节点上。

    1
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-nodeselector
      namespace: dev
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
      nodeSelector: 
        nodeenv: dev # 指定调度到具有nodeenv=dev标签的节点上
亲和性调度

kubernetes还提供了一种亲和性调度(Affinity)。它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。

Affinity主要分为三类:

  • nodeAffinity(node亲和性): 以node为目标,解决pod可以调度到哪些node的问题

    1
    pod.spec.affinity.nodeAffinity
      requiredDuringSchedulingIgnoredDuringExecution  Node节点必须满足指定的所有规则才可以,相当于硬限制
        nodeSelectorTerms  节点选择列表
          matchFields   按节点字段列出的节点选择器要求列表
          matchExpressions   按节点标签列出的节点选择器要求列表(推荐)
            key    键
            values 值
            operat or 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
      preferredDuringSchedulingIgnoredDuringExecution 优先调度到满足指定的规则的Node,相当于软限制 (倾向)
        preference   一个节点选择器项,与相应的权重相关联
          matchFields   按节点字段列出的节点选择器要求列表
          matchExpressions   按节点标签列出的节点选择器要求列表(推荐)
            key    键
            values 值
            operator 关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
    	weight 倾向权重,在范围1-100。
  • podAffinity(pod亲和性) : 以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题

    1
    pod.spec.affinity.podAffinity
      requiredDuringSchedulingIgnoredDuringExecution  硬限制
        namespaces       指定参照pod的namespace
        topologyKey      指定调度作用域
        labelSelector    标签选择器
          matchExpressions  按节点标签列出的节点选择器要求列表(推荐)
            key    键
            values 值
            operator 关系符 支持In, NotIn, Exists, DoesNotExist.
          matchLabels    指多个matchExpressions映射的内容
      preferredDuringSchedulingIgnoredDuringExecution 软限制
        podAffinityTerm  选项
          namespaces      
          topologyKey
          labelSelector
            matchExpressions  
              key    键
              values 值
              operator
            matchLabels 
        weight 倾向权重,在范围1-100
  • podAntiAffinity(pod反亲和性) : 以pod为目标,解决pod不能和哪些已存在pod部署在同一个拓扑域中的问题

污点和容忍
  • 污点(Taints)

    通过在Node上添加污点属性,来决定是否允许Pod调度过来

    污点的格式为:key=value:effect, key和value是污点的标签,effect描述污点的作用,支持如下三个选项:

    • PreferNoSchedule:kubernetes将尽量避免把Pod调度到具有该污点的Node上,除非没有其他节点可调度
    • NoSchedule:kubernetes将不会把Pod调度到具有该污点的Node上,但不会影响当前Node上已存在的Pod
    • NoExecute:kubernetes将不会把Pod调度到具有该污点的Node上,同时也会将Node上已存在的Pod驱离

    使用kubectl设置和去除污点的命令示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    # 设置污点
    kubectl taint nodes node1 key=value:effect

    # 去除污点
    kubectl taint nodes node1 key:effect-

    # 去除所有污点
    kubectl taint nodes node1 key-
  • 容忍(Toleration)

    污点就是拒绝,容忍就是忽略,Node通过污点拒绝pod调度上去,Pod通过容忍忽略拒绝

K8s:Namespace & Label

Posted on 2021-05-25 | In k8s |

Namespace

Namespace是kubernetes系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。

默认情况下,kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中,可能不想让两个Pod之间进行互相的访问,那此时就可以将两个Pod划分到不同的namespace下。kubernetes通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的”组”,以方便不同的组的资源进行隔离使用和管理。

可以通过kubernetes的授权机制,将不同的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用量、内存使用量等等,来实现租户可用资源的管理。

kubernetes在集群启动之后,会默认创建几个namespace

1
[root@master ~]# kubectl  get namespace
NAME              STATUS   AGE
default           Active   45h     #  所有未指定Namespace的对象都会被分配在default命名空间
kube-node-lease   Active   45h     #  集群节点之间的心跳维护,v1.13开始引入
kube-public       Active   45h     #  此命名空间下的资源可以被所有人访问(包括未认证用户)
kube-system       Active   45h     #  所有由Kubernetes系统创建的资源都处于这个命名空间

基本的操作

1
kubectl create/get/delete ns dev

Label

Label是kubernetes系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。

Label的特点:

  • 一个Label会以key/value键值对的形式附加到各种对象上,如Node、Pod、Service等等
  • 一个资源对象可以定义任意数量的Label ,同一个Label也可以被添加到任意数量的资源对象上去
  • Label通常在资源对象定义时确定,当然也可以在对象创建后动态添加或者删除

可以通过Label实现资源的多维度分组,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作。

标签定义完毕之后,还要考虑到标签的选择,这就要使用到Label Selector,即:

  • 基于等式的Label Selector

    name = slave: 选择所有包含Label中key=”name”且value=”slave”的对象

    env != production: 选择所有包括Label中的key=”env”且value不等于”production”的对象

  • 基于集合的Label Selector

    name in (master, slave): 选择所有包含Label中的key=”name”且value=”master”或”slave”的对象

    name not in (frontend): 选择所有包含Label中的key=”name”且value不等于”frontend”的对象

1
# 为pod资源打标签
[root@master ~]# kubectl label pod nginx-pod version=1.0 -n dev
pod/nginx-pod labeled

# 为pod资源更新标签
[root@master ~]# kubectl label pod nginx-pod version=2.0 -n dev --overwrite
pod/nginx-pod labeled

# 查看标签
[root@master ~]# kubectl get pod nginx-pod  -n dev --show-labels
NAME        READY   STATUS    RESTARTS   AGE   LABELS
nginx-pod   1/1     Running   0          10m   version=2.0

# 筛选标签
[root@master ~]# kubectl get pod -n dev -l version=2.0  --show-labels
NAME        READY   STATUS    RESTARTS   AGE   LABELS
nginx-pod   1/1     Running   0          17m   version=2.0
[root@master ~]# kubectl get pod -n dev -l version!=2.0 --show-labels
No resources found in dev namespace.

#删除标签
[root@master ~]# kubectl label pod nginx-pod version- -n dev
pod/nginx-pod labeled

K8s:集群环境搭建

Posted on 2021-05-17 | In k8s |

Kubeadm 是一个K8s 部署工具,提供kubeadm init 和kubeadm join,用于快速部署Kubernetes 集群。

  • 创建一个Master 节点kubeadm init
  • 将Node 节点加入到当前集群中$ kubeadm join

环境准备

  • VMWare
  • Centos 7.9 (3台)
角色 IP
master 192.168.36.10
node1 192.168.36.11
node2 192.168.36.12

系统安装和配置

VM的创建就不累述了,CPU 2C、MEM 2G、HARDWARE 40G、配置好网络(固定IP)、基础设施服务器。

  1. 为了方便集群节点间的直接调用,在这个配置一下主机名解析

    1
    192.168.36.10 master
    192.168.36.11 node1
    192.168.36.12 node2
  2. 设置时间同步

    kubernetes要求集群中的节点时间必须精确一致

    1
    [root@master ~]# systemctl start chronyd
    [root@master ~]# systemctl enable chronyd
  3. 禁用防火墙

    1
    [root@master ~]# systemctl stop firewalld
    [root@master ~]# systemctl disable firewalld
  4. 禁用Selinux

    1
    # 编辑 /etc/selinux/config 文件,修改SELINUX的值为disable
    # 注意修改完毕之后需要重启linux服务
    SELINUX=disabled
  5. 禁用Swap

    1
    # 编辑分区配置文件/etc/fstab,注释掉swap分区一行
    # 注意修改完毕之后需要重启linux服务
    vim /etc/fstab
    # /dev/mapper/centos-swap swap
  6. 修改内核参数

    1
    # 修改linux的内核采纳数,添加网桥过滤和地址转发功能
    # 编辑/etc/sysctl.d/kubernetes.conf文件,添加如下配置:
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    net.ipv4.ip_forward = 1
    
    # 重新加载配置
    [root@master ~]# sysctl -p
    # 加载网桥过滤模块
    [root@master ~]# modprobe br_netfilter
    # 查看网桥过滤模块是否加载成功
    [root@master ~]# lsmod | grep br_netfilter
  7. 配置ipvs功能

    1
    # 1.安装ipset和ipvsadm
    [root@master ~]# yum install ipset ipvsadmin -y
    # 2.添加需要加载的模块写入脚本文件
    [root@master ~]# cat <<EOF> /etc/sysconfig/modules/ipvs.modules
    #!/bin/bash
    modprobe -- ip_vs
    modprobe -- ip_vs_rr
    modprobe -- ip_vs_wrr
    modprobe -- ip_vs_sh
    modprobe -- nf_conntrack_ipv4
    EOF
    # 3.为脚本添加执行权限
    [root@master ~]# chmod +x /etc/sysconfig/modules/ipvs.modules
    # 4.执行脚本文件
    [root@master ~]# /bin/bash /etc/sysconfig/modeules/ipvs.modules
    # 5.查看对应的模块是否加载成功
    [root@master ~]# lsmod | grep -e -ip_vs -e nf_conntrack_ipv4

Docker安装

三个VM上都安装。

1
# 1、切换镜像源
[root@master ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d.docker-ce.repo

# 2、查看当前镜像源中支持的docker版本
# 先执行一下(yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo)
[root@master ~]# yum list docker-ce --showduplicates

# 3、安装特定版本的docker-ce
# 必须制定--setopt=obsoletes=0,否则yum会自动安装更高版本
[root@master ~]# yum install --setopt=obsoletes=0 docker-ce-18.06.3.ce-3.el7 -y

# 4、添加一个配置文件
#Docker 在默认情况下使用Vgroup Driver为cgroupfs,而Kubernetes推荐使用systemd来替代cgroupfs
[root@master ~]# mkdir /etc/docker
[root@master ~]# cat <<EOF> /etc/docker/daemon.json
{
	"exec-opts": ["native.cgroupdriver=systemd"],
	"registry-mirrors": ["https://kn0t2bca.mirror.aliyuncs.com"]
}
EOF

# 5、启动dokcer
[root@master ~]# systemctl restart docker
[root@master ~]# systemctl enable docker

# 6、验证
[root@master ~]# docker version
Client:
 Version:           18.06.3-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        d7080c1
 Built:             Wed Feb 20 02:26:51 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.3-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       d7080c1
  Built:            Wed Feb 20 02:28:17 2019
  OS/Arch:          linux/amd64
  Experimental:     false

K8s安装

安装组件

kubernetes的镜像在国外,速度比较慢,这里切换成国内的镜像源

1
# 1、编辑/etc/yum.repos.d/kubernetes.repo,添加下面的配置
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgchech=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
			http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

# 2、安装kubeadm、kubelet和kubectl
[root@master ~]# yum install --setopt=obsoletes=0 kubeadm-1.17.4-0 kubelet-1.17.4-0 kubectl-1.17.4-0 -y

# 3、配置kubelet的cgroup
#编辑/etc/sysconfig/kubelet, 添加下面的配置
KUBELET_CGROUP_ARGS="--cgroup-driver=systemd"
KUBE_PROXY_MODE="ipvs"

# 4、设置kubelet开机自启
[root@master ~]# systemctl enable kubelet
准备集群镜像

Kubernetes几乎所有的安装组件和Docker镜像都放在goolge自己的网站上,这里的解决办法是从阿里云镜像仓库下载镜像,拉取到本地以后改回默认的镜像tag。

1
cat <<EOF> ./k8simage.sh
#!/bin/bash
images=(
	kube-apiserver:v1.17.4
	kube-controller-manager:v1.17.4
	kube-scheduler:v1.17.4
	kube-proxy:v1.17.4
	pause:3.1
	etcd:3.4.3-0
	coredns:1.6.5
)
for imageName in ${images[@]};do
	docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
	docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
	docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName 
done
EOF

[root@master ~]# chmod 755 k8simage.sh
[root@master ~]# ./k8simage.sh

集群验证

集群初始化
  1. master上操作

    1
    [root@master ~]# kubeadm init --apiserver-advertise-address=192.168.36.10 --kubernetes-version v1.17.4 --service-cidr=10.96.0.0/12 --pod-network-cidr=10.244.0.0/16  --image-repository registry.aliyuncs.com/google_containers
    W1013 10:37:33.958785    1872 validation.go:28] Cannot validate kube-proxy config - no validator is available
    W1013 10:37:33.958821    1872 validation.go:28] Cannot validate kubelet config - no validator is available
    [init] Using Kubernetes version: v1.17.4
    [preflight] Running pre-flight checks
    [preflight] Pulling images required for setting up a Kubernetes cluster
    [preflight] This might take a minute or two, depending on the speed of your internet connection
    [preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
    [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
    [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
    [kubelet-start] Starting the kubelet
    [certs] Using certificateDir folder "/etc/kubernetes/pki"
    [certs] Generating "ca" certificate and key
    [certs] Generating "apiserver" certificate and key
    [certs] apiserver serving cert is signed for DNS names [master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.36.10]
    [certs] Generating "apiserver-kubelet-client" certificate and key
    [certs] Generating "front-proxy-ca" certificate and key
    [certs] Generating "front-proxy-client" certificate and key
    [certs] Generating "etcd/ca" certificate and key
    [certs] Generating "etcd/server" certificate and key
    [certs] etcd/server serving cert is signed for DNS names [master localhost] and IPs [192.168.36.10 127.0.0.1 ::1]
    [certs] Generating "etcd/peer" certificate and key
    [certs] etcd/peer serving cert is signed for DNS names [master localhost] and IPs [192.168.36.10 127.0.0.1 ::1]
    [certs] Generating "etcd/healthcheck-client" certificate and key
    [certs] Generating "apiserver-etcd-client" certificate and key
    [certs] Generating "sa" key and public key
    [kubeconfig] Using kubeconfig folder "/etc/kubernetes"
    [kubeconfig] Writing "admin.conf" kubeconfig file
    [kubeconfig] Writing "kubelet.conf" kubeconfig file
    [kubeconfig] Writing "controller-manager.conf" kubeconfig file
    [kubeconfig] Writing "scheduler.conf" kubeconfig file
    [control-plane] Using manifest folder "/etc/kubernetes/manifests"
    [control-plane] Creating static Pod manifest for "kube-apiserver"
    [control-plane] Creating static Pod manifest for "kube-controller-manager"
    W1013 10:40:01.037622    1872 manifests.go:214] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
    [control-plane] Creating static Pod manifest for "kube-scheduler"
    W1013 10:40:01.039721    1872 manifests.go:214] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
    [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
    [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
    [apiclient] All control plane components are healthy after 20.522009 seconds
    [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
    [kubelet] Creating a ConfigMap "kubelet-config-1.17" in namespace kube-system with the configuration for the kubelets in the cluster
    [upload-certs] Skipping phase. Please see --upload-certs
    [mark-control-plane] Marking the node master as control-plane by adding the label "node-role.kubernetes.io/master=''"
    [mark-control-plane] Marking the node master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
    [bootstrap-token] Using token: 9ejhyb.0bbmx3l90b9xkd0j
    [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
    [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
    [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
    [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
    [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
    [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
    [addons] Applied essential addon: CoreDNS
    [addons] Applied essential addon: kube-proxy
    
    Your Kubernetes control-plane has initialized successfully!
    
    To start using your cluster, you need to run the following as a regular user:
    
      mkdir -p $HOME/.kube
      sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
      sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
    You should now deploy a pod network to the cluster.
    Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
      https://kubernetes.io/docs/concepts/cluster-administration/addons/
    
    Then you can join any number of worker nodes by running the following on each as root:
    
    kubeadm join 192.168.36.10:6443 --token 9ejhyb.0bbmx3l90b9xkd0j \
        --discovery-token-ca-cert-hash sha256:b206e4be9fbe0d49d8e7df1c9e783efc590471bbf5510ae79be5c3a6626748b4
  2. cluster配置

    根据提示操作

    1
    [root@master ~]# mkdir -p $HOME/.kube
    [root@master ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    [root@master ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
  3. node上操作

    根据上面的提示执行下面操作

    1
    [root@node2 ~]# kubeadm join 192.168.36.10:6443 --token 9ejhyb.0bbmx3l90b9xkd0j \
    >     --discovery-token-ca-cert-hash sha256:b206e4be9fbe0d49d8e7df1c9e783efc590471bbf5510ae79be5c3a6626748b4
    W1013 10:56:24.205622    2554 join.go:346] [preflight] WARNING: JoinControlPane.controlPlane settings will be ignored when control-plane flag is not set.
    [preflight] Running pre-flight checks
    [preflight] Reading configuration from the cluster...
    [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
    [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.17" ConfigMap in the kube-system namespace
    [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
    [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
    [kubelet-start] Starting the kubelet
    [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
    
    This node has joined the cluster:
    * Certificate signing request was sent to apiserver and a response was received.
    * The Kubelet was informed of the new secure connection details.
    
    Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
  4. 验证nodes

    1
    [root@master ~]# kubectl get nodes
    NAME     STATUS     ROLES    AGE    VERSION
    master   NotReady   master   22m    v1.17.4
    node1    NotReady   <none>   6m1s   v1.17.4
    node2    NotReady   <none>   6m8s   v1.17.4
  5. 安装网络插件

    只在master操作

    外网访问不了,直接把文件内容Copy进去

    1
    # https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    # https://github.com/flannel-io/flannel/tree/master/Documentation/kube-flannel.yml
    
    cat <<EOF> ./kube-flannel.yml
    ---
    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: psp.flannel.unprivileged
      annotations:
        seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default
        seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default
        apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
        apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
    spec:
      privileged: false
      volumes:
      - configMap
      - secret
      - emptyDir
      - hostPath
      allowedHostPaths:
      - pathPrefix: "/etc/cni/net.d"
      - pathPrefix: "/etc/kube-flannel"
      - pathPrefix: "/run/flannel"
      readOnlyRootFilesystem: false
      # Users and groups
      runAsUser:
        rule: RunAsAny
      supplementalGroups:
        rule: RunAsAny
      fsGroup:
        rule: RunAsAny
      # Privilege Escalation
      allowPrivilegeEscalation: false
      defaultAllowPrivilegeEscalation: false
      # Capabilities
      allowedCapabilities: ['NET_ADMIN', 'NET_RAW']
      defaultAddCapabilities: []
      requiredDropCapabilities: []
      # Host namespaces
      hostPID: false
      hostIPC: false
      hostNetwork: true
      hostPorts:
      - min: 0
        max: 65535
      # SELinux
      seLinux:
        # SELinux is unused in CaaSP
        rule: 'RunAsAny'
    ---
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: flannel
    rules:
    - apiGroups: ['extensions']
      resources: ['podsecuritypolicies']
      verbs: ['use']
      resourceNames: ['psp.flannel.unprivileged']
    - apiGroups:
      - ""
      resources:
      - pods
      verbs:
      - get
    - apiGroups:
      - ""
      resources:
      - nodes
      verbs:
      - list
      - watch
    - apiGroups:
      - ""
      resources:
      - nodes/status
      verbs:
      - patch
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: flannel
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: flannel
    subjects:
    - kind: ServiceAccount
      name: flannel
      namespace: kube-system
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: flannel
      namespace: kube-system
    ---
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: kube-flannel-cfg
      namespace: kube-system
      labels:
        tier: node
        app: flannel
    data:
      cni-conf.json: |
        {
          "name": "cbr0",
          "cniVersion": "0.3.1",
          "plugins": [
            {
              "type": "flannel",
              "delegate": {
                "hairpinMode": true,
                "isDefaultGateway": true
              }
            },
            {
              "type": "portmap",
              "capabilities": {
                "portMappings": true
              }
            }
          ]
        }
      net-conf.json: |
        {
          "Network": "10.244.0.0/16",
          "Backend": {
            "Type": "vxlan"
          }
        }
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: kube-flannel-ds
      namespace: kube-system
      labels:
        tier: node
        app: flannel
    spec:
      selector:
        matchLabels:
          app: flannel
      template:
        metadata:
          labels:
            tier: node
            app: flannel
        spec:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: kubernetes.io/os
                    operator: In
                    values:
                    - linux
          hostNetwork: true
          priorityClassName: system-node-critical
          tolerations:
          - operator: Exists
            effect: NoSchedule
          serviceAccountName: flannel
          initContainers:
          - name: install-cni
            image: quay.io/coreos/flannel:v0.14.0
            command:
            - cp
            args:
            - -f
            - /etc/kube-flannel/cni-conf.json
            - /etc/cni/net.d/10-flannel.conflist
            volumeMounts:
            - name: cni
              mountPath: /etc/cni/net.d
            - name: flannel-cfg
              mountPath: /etc/kube-flannel/
          containers:
          - name: kube-flannel
            image: quay.io/coreos/flannel:v0.14.0
            command:
            - /opt/bin/flanneld
            args:
            - --ip-masq
            - --kube-subnet-mgr
            resources:
              requests:
                cpu: "100m"
                memory: "50Mi"
              limits:
                cpu: "100m"
                memory: "50Mi"
            securityContext:
              privileged: false
              capabilities:
                add: ["NET_ADMIN", "NET_RAW"]
            env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            volumeMounts:
            - name: run
              mountPath: /run/flannel
            - name: flannel-cfg
              mountPath: /etc/kube-flannel/
          volumes:
          - name: run
            hostPath:
              path: /run/flannel
          - name: cni
            hostPath:
              path: /etc/cni/net.d
          - name: flannel-cfg
            configMap:
              name: kube-flannel-cfg
    EOF
    1
    [root@master ~]# kubectl apply -f kube-flannel.yml 
    podsecuritypolicy.policy/psp.flannel.unprivileged created
    clusterrole.rbac.authorization.k8s.io/flannel created
    clusterrolebinding.rbac.authorization.k8s.io/flannel created
    serviceaccount/flannel created
    configmap/kube-flannel-cfg created
    daemonset.apps/kube-flannel-ds created
  6. 等待它安装完毕 发现已经是 集群的状态已经是Ready

    1
    [root@master ~]# kubectl get nodes
    NAME     STATUS   ROLES    AGE   VERSION
    master   Ready    master   29m   v1.17.4
    node1    Ready    <none>   13m   v1.17.4
    node2    Ready    <none>   13m   v1.17.4
集群测试
1
# 创建一个Nginx服务
[root@master ~]# kubectl create deployment nginx  --image=nginx:1.14-alpine
deployment.apps/nginx created
# 暴露端口
[root@master ~]# kubectl expose deploy nginx  --port=80 --target-port=80  --type=NodePort
service/nginx exposed

验证:

1
[root@master ~]# curl master:32020
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@master ~]# curl node1:32020
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@master ~]# curl node2:32020
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

K8s:入门介绍

Posted on 2021-05-13 | In k8s |

kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:

  • 自我修复:一旦某一个容器崩溃,能够在1秒中左右迅速启动新的容器
  • 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
  • 服务发现:服务可以通过自动发现的形式找到它所依赖的服务
  • 负载均衡:如果一个服务起动了多个容器,能够自动实现请求的负载均衡
  • 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
  • 存储编排:可以根据容器自身的需求自动创建存储卷

kubernetes组件

一个kubernetes集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件。

master:集群的控制平面,负责集群的决策 ( 管理 )

ApiServer : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制

Scheduler : 负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上

ControllerManager : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等

Etcd :负责存储集群中各种资源对象的信息

node:集群的数据平面,负责为容器提供运行环境 ( 干活 )

Kubelet : 负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器

KubeProxy : 负责提供集群内部的服务发现和负载均衡

Docker : 负责节点上容器的各种操作

kubernetes常用概念

Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控

Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器的运行

Pod:kubernetes的最小控制单元,容器都是运行在pod中的,一个pod中可以有1个或者多个容器

Controller:控制器,通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等等

Service:pod对外服务的统一入口,下面可以维护者同一类的多个pod

Label:标签,用于对pod进行分类,同一类pod会拥有相同的标签

NameSpace:命名空间,用来隔离pod的运行环境

1…345…40
唐胡璐

唐胡璐

i just wanna live while i am alive

393 posts
42 categories
74 tags
RSS
LinkedIn Weibo GitHub E-Mail
Creative Commons
© 2022 唐胡璐
Powered by Hexo
|
Theme — NexT.Pisces v5.1.4