1. 概念入门

  • master节点
  • worker节点
  • Pod Kubernetes最小管理单位,一个节点可以拥有多个Pod,一个Pod可以拥有多个容器

2. 安装

2.1 minikube

安装教程: https://minikube.sigs.k8s.io/docs/start/

2.2 腾讯云集群

按步骤很容易起一个Kubernetes集群

3. 常用命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
kubectl apply -f app.yaml         # 部署应用
kubectl get deployment            # 查看 deployment
kubectl get pod -o wide           # 查看 pod
kubectl describe pod pod-name     # 查看 pod 详情
kubectl logs pod-name             # 查看 log
kubectl exec -it pod-name -- bash # 进入 Pod 容器终端, -c container-name 可以指定进入哪个容器。
kubectl scale deployment test-k8s --replicas=5  # 伸缩扩展副本
kubectl port-forward pod-name 8090:8080         # 把集群内端口映射到节点
kubectl rollout history deployment test-k8s     # 查看历史
kubectl rollout undo deployment test-k8s        # 回到上个版本
kubectl rollout undo deployment test-k8s --to-revision=2   # 回到指定版本
kubectl delete deployment test-k8s                         # 删除部署

4. Pod

  • 每个 Pod 都在每个地址族中获得一个唯一的 IP 地址。
  • Pod 中的每个容器共享网络名字空间,包括 IP 地址和网络端口。 Pod 内 的容器可以使用 localhost 互相通信。
  • Pod生命周期
    • Pod 遵循一个预定义的生命周期,起始于 Pending 阶段,如果至少 其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以 失败状态结束而进入 Succeeded 或者 Failed 阶段。
  • 容器重启策略
    • Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
  • 容器探针
    • probe 是由 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 既可以在容器内执行代码,也可以发出一个网络请求。
    • 探针的四种检查机制:exec、grpc、httpGet、tcpSocket
    • 探测的结果:Success、Failure、Unknown
    • 探测的类型:livenessProbe、readinessProbe、startupProbe
  • Pod的终止
    • 一般不应武断地使用 KILL 信号终止它们,导致这些进程没有机会 完成清理操作。
    • 在存在强制关闭设施的前提下, kubelet 会尝试体面地终止 Pod。
    • 通常情况下,容器运行时会发送一个 TERM 信号到每个容器中的主进程。 很多容器运行时都能够注意到容器镜像中 STOPSIGNAL 的值,并发送该信号而不是 TERM。 一旦超出了体面终止限期,容器运行时会向所有剩余进程发送 KILL 信号,之后 Pod 就会被从 API 服务器 上移除。如果 kubelet 或者容器运行时的管理服务在等待进程终止期间被重启, 集群会从头开始重试,赋予 Pod 完整的体面终止限期。
  • Init 容器
    • Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。
    • Pod 可以有一个或多个先于应用容器启动的 Init 容器。
    • Init 容器必须在应用容器启动之前运行完成,因此 Init 容器 提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。 一旦前置条件满足,Pod 内的所有的应用容器会并行启动。
    • 如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。如果 Pod 对应的 restartPolicy 值为 “Never”,并且 Pod 的 Init 容器失败, 则 Kubernetes 会将整个 Pod 状态设置为失败。
    • 为 Pod 设置 Init 容器需要添加 initContainers 字段
  • 临时容器
    • 当由于容器崩溃或容器镜像不包含调试工具而导致 kubectl exec 无用时, 临时容器对于交互式故障排查很有用。

4.1 一个简单的例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

4.2 Pod template

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: batch/v1
kind: Job
metadata:
  name: hello
spec:
  template:
    spec:
      containers:
      - name: hello
        image: busybox:1.28
        command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
      restartPolicy: OnFailure

当某工作负载的 Pod 模板被改变时,控制器会基于更新的模板 创建新的 Pod 对象而不是对现有 Pod 执行更新或者修补操作。

4.3 一个Init容器的例子(先等待myservice启动,再等待mydb启动)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

5. 工作负载资源分类

  • Deployment 适合无状态应用,所有pod等价,可替代
  • StatefulSet 有状态的应用,适合数据库这种类型
  • DaemonSet 在每个节点上跑一个Pod,可以用来做节点监控、节点日志收集
  • Job & CronJob Job用来表达的是一次性任务,而CronJob会根据其时间规划反复运行

5.1 Deployment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
  • selector 字段定义 Deployment 如何查找要管理的 Pods。 在这里,你选择在 Pod 模板中定义的标签(app: nginx)。 不过,更复杂的选择规则是也可能的,只要 Pod 模板本身满足所给规则即可。
  • yaml编写,请参考Deployment编写规约
  • 运行 kubectl get deployments 检查 Deployment 是否已创建
  • 获取 Deployment 描述信息:kubectl describe deployment
  • 更新deployment:使用kubectl setkubectl edit
  • 回滚deploymnet:kubectl rollout undo
  • 检查 Deployment 上线历史: kubectl rollout history deployment_name
  • 缩放 Deployment: kubectl scale deployment_name --replicas=10
  • 暂停 Deployment: kubectl rollout pause

5.2 StatefulSet

 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
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb
spec:
  serviceName: mongodb
  replicas: 3
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
        - name: mongo
          image: mongo:4.4
          # IfNotPresent 仅本地没有镜像时才远程拉,Always 永远都是从远程拉,Never 永远只用本地镜像,本地没有则报错
          imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
  name: mongodb
spec:
  selector:
    app: mongodb
  type: ClusterIP
  # HeadLess
  clusterIP: None
  ports:
    - port: 27017
      targetPort: 27017
  • StatefulSet 是用来管理有状态的应用,例如数据库。
  • StatefulSet 特性
    • Service 的 CLUSTER-IP 是空的,Pod 名字也是固定的。
    • Pod 创建和销毁是有序的,创建是顺序的,销毁是逆序的。
    • Pod 重建不会改变名字,除了IP,所以不要用IP直连

5.3 DaemonSet

5.4 Job & CronJob

6. 数据持久化

  • Storage Class (SC)
    • 将存储卷划分为不同的种类,例如:SSD,普通磁盘,本地磁盘,按需使用
    •  1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
        apiVersion: storage.k8s.io/v1
        kind: StorageClass
        metadata:
        name: slow
        provisioner: kubernetes.io/aws-ebs
        parameters:
        type: io1
        iopsPerGB: "10"
        fsType: ext4
      
      
  • Persistent Volumne (PV)
    • 描述卷的具体信息,例如磁盘大小,访问模式
    •  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
      
        apiVersion: v1
        kind: PersistentVolume
        metadata:
        name: mongodata
        spec:
        capacity:
            storage: 2Gi
        volumeMode: Filesystem  # Filesystem(文件系统) Block(块)
        accessModes:
            - ReadWriteOnce       # 卷可以被一个节点以读写方式挂载
        persistentVolumeReclaimPolicy: Delete
        storageClassName: local-storage
        local:
            path: /root/data
        nodeAffinity:
            required:
            # 通过 hostname 限定在某个节点创建存储卷
            nodeSelectorTerms:
                - matchExpressions:
                    - key: kubernetes.io/hostname
                    operator: In
                    values:
                        - node2
      
            ```
      
  • Persistent Volumne Claim (PVC)
    • 对存储需求的一个申明,可以理解为一个申请单,系统根据这个申请单去找一个合适的 PV。还可以根据 PVC 自动创建 PV。
    •  1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
        apiVersion: v1
        kind: PersistentVolumeClaim
        metadata:
        name: mongodata
        spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: "local-storage"
        resources:
            requests:
            storage: 2Gi
      

例如在腾讯云上,编写PVC,会自动生成PV和SC,资源申请完成后,我们只需把磁盘挂载到对应的statefulset即可。

7 Service

  • Service管理一组pod,通过label关联对应的pod
  • pod重建,不会导致service重建
  • Service提供了负载均衡的功能,自动转发流量到不同的 Pod
  • Service 可对集群外部提供访问端口
  • Service 内部可以通过名字访问

7.1 Service相关命令

1
2
3
kubectl get svc                 # 查看所有Service
kubectl describe svc svc_name   # 查看Service详细

7.2 例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: Service
metadata:
    name test-k8s-service
spec:
    selector:
        app: test-k8s-service
    type: ClusterIP  # 可选项:NodePort, None, Loadbalancer
    ports:
        - port: 8080     # 本service端口
        targetPort: 8080 # 容器端口

对外暴露服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
  name: test-k8s
spec:
  selector:
    app: test-k8s
  type: NodePort  
  ports:
    - port: 8080        # 本 Service 的端口
      targetPort: 8080  # 容器端口
      nodePort: 31000   # 节点端口,范围固定 30000 ~ 32767

  • type
    • ClusterIP: 集群内可访问
    • NodePort: 节点可访问
    • LoadBalancer: 负载均衡模式(需要负载均衡器才可用)
    • Headless:适合数据库,clusterIp 设置为 None 就变成 Headless 了,不会再分配 IP

8. ConfigMap & Secret

ConfigMap和Secret这两种Kind的支持,使得我门更好的管理配置和秘钥

8.1 ConfigMap

1
2
3
4
5
6
apiVersion: v1
kind: ConfigMap
metadata:
  name: mongo-config
data:
  mongoHost: mongodb-0.mongodb
  • 查看configmap: kubectl get configmap mongo-config -o yaml

8.2 Secret

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
type: Opaque # Opaque 用户定义的任意数据
data:
  mongo-username: bW9uZ291c2Vy  # base64
  mongo-password: bW9uZ29wYXNz

8.3 使用方法

 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
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
        - name: mongo
          image: mongo:4.4
          imagePullPolicy: IfNotPresent
          env:
          - name: MONGO_INITDB_ROOT_USERNAME
            valueFrom:
              secretKeyRef:
                name: mongo-secret
                key: mongo-username
          - name: MONGO_INITDB_ROOT_PASSWORD
            valueFrom:
              secretKeyRef:
                name: mongo-secret
                key: mongo-password
          # Secret 的所有数据定义为容器的环境变量,Secret 中的键名称为 Pod 中的环境变量名称
          # envFrom:
          # - secretRef:
          #     name: mongo-secret

挂载为文件(更适合证书)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret

9. Ingress

  • Ingress 为外部访问集群提供了一个 统一 入口,避免了对外暴露集群端口;
  • Ingress 功能类似 Nginx,可以根据域名、路径把请求转发到不同的 Service。
  • 可以配置 https

和Loadbalancer的区别:

  • LoadBalancer 需要对外暴露端口,不安全;
  • 无法根据域名、路径转发流量到不同 Service,多个 Service 则需要开多个 LoadBalancer;
  • 功能单一,无法配置 https

要使用 Ingress,需要一个负载均衡器 + Ingress Controller。
如果是云服务商,会自动给你配置,否则你的外部 IP 会是 “pending” 状态,无法使用。

10. 包管理工具Helm

  • Helm是kubernetes下的包管理工具,每个包被称为chart。
  • 使用helm,我们可以很方便搭建集群,如MySQL集群

10.1 helm的使用

10.2 编写自己的chart