美文网首页
K8S备忘录

K8S备忘录

作者: winlinvip | 来源:发表于2021-03-04 06:46 被阅读0次

    K8S的概念:

    • Node(节点),节点机器,可以是物理机或虚拟机,比如ECS,运行了各种进程和docker等。
    • Pod(容器组),应用的执行单元,创建和部署的单元;包含一个或多个容器,存储和网络资源,以及配置项。
    • Controller(应用),管理Pods、复制和自愈,例如Node失败时自动迁移Pods到其他节点。
    • Deployment(无状态),无状态Controller(应用)。
    • Container(容器),一个Pod可以跑N>=1个Container,这些Container可以共享一些东西。

    K8S命令

    在macOS下可以直接用brew安装:

    brew install kubectl
    

    常用的K8S命令:

    kubectl cluster-info
    kubectl get cm --all-namespaces
    kubectl get cm -n kube-system
    kubectl get cm/srs3-config
    kubectl get cm/cluster-info -n kube-public -o yaml
    kubectl get cm/cluster-info -n kube-public -o json
    kubectl get deploy
    kubectl get deploy/nginx-deployment -o yaml
    kubectl get deploy/nginx-deployment -o json
    kubectl get rs
    kubectl get rs -w
    kubectl get pods
    kubectl get pods --show-labels
    kubectl edit deployment.v1.apps/nginx-deployment
    kubectl api-resources # 可以查询到缩写。
    kubectl get services
    kubectl get svc/nginx-service -o yaml
    kubectl exec srs-deployment-f4cd6b6cc-c74bm -c nginx env
    kubectl get pods -o jsonpath="{.items[*].spec.containers[*].name}"
    kubectl delete po/srs-origin-deployment-577cf4c7b7-zp7bs --force --grace-period=0
    kubectl get po --show-labels
    kubectl label deploy/srs-origin-deployment app=srs --overwrite
    kubectl label po/srs-origin-deployment-6b4fcf6674-qphdz app=srs --overwrite
    kubectl exec srs-edge-deploy-58d9999b7c-f4rtr -- ./objs/srs -v
    kubectl set image deploy/srs-edge-deploy srs=ossrs/srs:v4.0.6
    kubectl set image deploy/srs-edge-deploy srs=ossrs/srs:v4.0.6 --record
    kubectl rollout history deploy/srs-edge-deploy
    kubectl get rs
    kubectl get rs -w # 可以Watch变化。
    kubectl scale --replicas=3 deploy/srs-edge-deploy
    kubectl logs srs-edge-deploy-d4cfc9d8b-5wnw7
    kubectl describe po/srs-edge-deploy-d4cfc9d8b-85nkf |grep -A 3 Events
    kubectl get nodes
    kubectl describe nodes/cn-beijing.172.17.232.153
    kubectl config get-contexts
    

    切换集群

    查看集群:

    kubectl config get-contexts
    

    设置默认集群:

    kubectl config use-context kubernetes-admin-xxx
    

    ConfigMap保存证书

    ConfigMap可以配置多个文件,比如证书的私钥(*.key)和公钥(*.pem),后台添加配置,或者用yaml:

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: https-config
    data:
      https.key: |-
        -----BEGIN RSA PRIVATE KEY-----
        MIIEowIBAAKCAQEA8mEyACKNJcxAfPWvAYr0uy/wVtd16LPEpy7w1l9WD9+SBsOj
        n0QZSc2+y/mEpwXA65irqUply42NabB6rgfsfbcLra8SA5CbyHtrIP4fT6jnBA85
        Jzmznp/q/1n4nlfaqawFyOB2IzPjPiwzexN/gv2wWC+5wSQ9yq2k
        -----END RSA PRIVATE KEY-----
      https.pem: |-
        -----BEGIN CERTIFICATE-----
        MIIFfjCCBGagAwIBAgIQD8reYBHHOc99faMYlJ0lazANBgkqhkiG9w0BAQsFADBu
        MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
        d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
        -----END CERTIFICATE-----
    EOF
    

    挂到容器作为配置文件:

    cat <<EOF | kubectl apply -f -
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: srs
      labels:
        app: srs
    spec:
      selector:
        matchLabels:
          app: srs
      template:
        metadata:
          labels:
            app: srs
        spec:
          volumes:
            - name: ssl-volume
              configMap:
                name: https-config
          containers:
          - name: srs
            image: registry.cn-hangzhou.aliyuncs.com/ossrs/srs:3
            imagePullPolicy: IfNotPresent
            volumeMounts:
              - name: ssl-volume
                mountPath: /usr/local/srs/etc
    EOF
    

    可以查看etc目录,就有了证书文件:

    $ kubectl get pods -l app=srs
    NAME                   READY   STATUS    RESTARTS   AGE
    srs-77b446fbfc-ftz7c   1/1     Running   0          4m50s
    
    $ kubectl exec srs-77b446fbfc-ftz7c -- ls -lh etc
    lrwxrwxrwx 1 root root 16 Feb  1 07:06 https.key -> ..data/https.key
    lrwxrwxrwx 1 root root 16 Feb  1 07:06 https.pem -> ..data/https.pem
    

    Volume

    Volumes,docker有这个概念但比较简单且无生命周期管理,k8s提供各种复杂的volume,而且volume是随pod的生命周期(大于container)。

    emptyDir,临时的空目录,在pod删除时会情况,container crash后目录数据还在,可用于crash后的恢复。

    比如SRS写到nginx目录后,nginx可以分发切片文件。

    • nginx默认目录是:/usr/share/nginx/html
    • SRS的默认目录是:/usr/local/srs/objs/nginx/html

    起一个Pod运行这两个容器,共享这个目录,这样就可以实现SRS写Nginx读了。

    Container Args

    设置container的命令和参数

    使用command和args,command是命令,args是它的参数,一般需要一起设置。可以command指定为/bin/sh,用shell执行脚本,参数就是:

    command: ["/bin/sh"]
    args: ["-c", "cp -R ./objs/nginx/html/* /tmp/html/; sleep infinity"]
    

    也可以在里面写for循环:

    command: ["/bin/sh"]
    args: ["-c", "while true; do echo hello; sleep 10;done"]
    

    还可以写成数组的方式,字符串用长字符串换行:

    command: ["/bin/sh"]
    args:
    - "-c"
    - >
      while true; do
        ffmpeg -re -i ./doc/source.200kbps.768x320.flv \
          -c copy -f flv rtmp://srs/live/livestream
      done
    

    可以用脚本做初始化的事情。也可以只用args,会从args中解析出command:

    args:
    - /bin/sh
    - -c
    - echo hello
    

    Resource

    管理容器使用的计算资源,Resource

    可以创建Pod时指定需要的CPU和内存,这样调度时知道调度到哪个节点;还可以指定资源的限额。资源限额定义,Quota

    资源的要求和限制,指定在:

    • spec.containers[].resources.limits.cpu
    • spec.containers[].resources.limits.memory
    • spec.containers[].resources.requests.cpu
    • spec.containers[].resources.requests.memory

    CPU,比如cpu: 0.1就是100m,m就是千分之,millicpu,millicores。
    Memory,比如memory: 100Mi就是100MiB,还有Ki,Gi,Ti,Pi。

    limits是最多使用的限制;requests是需要使用的,也就是要求的资源

    0<=Request<=Limit<=Infinity (如果Limit为0表示不对资源进行限制,这时可以小于Request)
    

    关于调度

    • 调度时会根据request的资源,保障总的request资源小于Node容量。所以request的资源,是比实际运行的要小的。
    • 或者可以认为,低峰期时空闲时CPU是1%,高峰时可能request到30%,limit到50%。调度时就根据各个Pod的30%作为上限。

    关于limit

    • K8S启动容器时,会把request cpu传递到容器runtime中,docker run的-c参数:
      • 默认是1024,至少是2。如果某个容器是空闲的,其他容器可以使用剩下的全部的CPU。某个容器能使用的最多CPU是变化的。
      • 例如如果一个是1024,两个是512,如果容器内的CPU都跑到100%了,那么实际上第一个是50%,剩下两个是25%。
      • 如果再加第四个容器也是1024,那么第一个是33%,第二和三是16.5%,第四是33%。
      • 虽然每个容器的CPU份额是小于100%的,但在多核的机器上可能让多个CPU跑100%。
      • 比如有3个CPU,第一个容器是512,另外是1024,那么可能CPU0是100%跑第一个容器,CPU1和CPU2也是100%跑第二个容器。从系统总体看CPU是300%,100%给了第一个容器,200%给了第二个容器。
    • 而limit cpu,则会传递到docker的cpu-quota参数。
    • 而limit memory,则会传递到docker的memory参数:
      • 如果容器超过内存限制limits.memory,很可能重启。内存和磁盘是不可压缩资源。
      • 如果容器超过要求的内存requests.memory,在节点超过能力时会被迁移。
      • 容器可能会被允许超过CPU的限制,但不会因为CPU过高而被KILL。CPU是可压缩资源。
    • 如果容器因为资源限制被终止
      • 查看容器的事件:kubectl describe po/srs-edge-deploy-d4cfc9d8b-85nkf |grep -A 3 Events
    • 查看节点调度的资源情况:kubectl describe nodes/cn-beijing.172.17.232.153

    改进:

    关于QoS

    • Guranteed,最高保障,request和limit相等,只指定了limit(就默认request等于limit)。
      *Burstable,Strong wish,强烈要求,request和limit有设置,但不相等。
    • Best-Effort,最好能支持,完全不设置。

    OOM时KILL的顺序:最先KILL Best-Effort,然后是Burstable,最后是Guranteed。

    Config Reload

    ConfigMap修改后,文件会变。

    注意:fsnotify signal可能因为符号链接收不到。

    Linux是使用inotify机制,用inotify_init返回fd,watch后如果有变化可以read出来。

    可以侦听所有事件:IN_ALL_EVENTS,但主要是IN_MODIFY和IN_CREATE

    返回的内容转换成结构体:inotify_event

    YAML格式

    -表示列表,比如ports可以指定多个,所以就以-开头。

    管道命令行apply

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    EOF
    

    可以把多个yaml写在一起,用三个横杠分割,比如stateful

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Service
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    EOF
    

    配置镜像拉取,如果存在就不拉取images

    spec.containers[*].imagePullPolicy: IfNotPresent
    

    如果总是拉取,则设置为Always

    Service

    Service就是如何让Pods提供服务,或微服务,涉及服务发现和负载均衡。

    一般服务发现使用的是label selector,有时候也需要无selector的Service(必须后端是另外一个K8S或非Pod)。标签(label)就是分组的一种方式了,或者一种ID。

    定义服务时,需要指定selector比如app=nginx,指定服务端口port,以及后端端口targetPort(默认等于port)。

    注意targetPort可以是字符串,会解析成对应的端口,这样后端服务会比较灵活。

    下面是一个服务的描述。

    cat <<EOF | kubectl apply -f -
    kind: Service
    apiVersion: v1
    metadata:
      name: nginx-service
    spec:
      selector:
        app: nginx
      ports:
        - protocol: TCP
          port: 80
    EOF
    

    查询该服务:

    $ kubectl get svc/nginx-service
    NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    nginx-service   ClusterIP   172.21.7.190   <none>        80/TCP    3m13s
    

    服务是由kube-proxy分配的VIP并进行代理,没有采用DNS因为有缓存等问题:

    kube-proxy有几种不同的代理方式:

    • user space proxy mode,用户空间代理模式,proxy为每个service侦听一个端口,通过iptables将服务的请求转发到这个端口然后转给pod。
    • iptables proxy mode,iptables代理,proxy为每个service新增一条转发规则,负载高应该是内核netfilter转发,但出错后不会重试。
    • IPVS proxy mode,1.11后支持了IPVS代理,使用的是内核的netlink,比iptables性能更高吞吐率也更高。

    如果杀掉nginx的pod,如果只有一个pod会服务不可用,但过一会儿K8S会重新启动pod,服务就可以了。

    Service Type

    ServiceTypes服务类型,一般ClusterIP就是内部服务,还有其他的:

    • ClusterIP,默认就是这种,集群内部可以访问。分配的是Service网段IP(172.21.*),有内部端点无外部端点。
    • NodePort,绑定到Node上,也就是Node(ECS)网段(172.17.*),会自动创建ClusterIP服务。外部可以通过Node的IP访问服务。
    • LoadBalancer,通过云服务的负载均衡实现,会自动创建NodePort和ClusterIP。外部访问的是负载均衡。
    • ExternalName,绑定到CNAME,比如foo.example.com,不会创建代理,coredns1.7及以上才支持。

    默认是ClusterIP,看到内网的IP(ClusterIP),但无外部IP(ExternalIP),ClusterIP 172.21.89.226 <none> 80/TCP,可访问性如下:

    • nginx的realserver是在172.17.232.153
    • nginx的POD的IP,可在跳板机访问:curl http://172.20.0.24
    • nginx-service的IP是172.21.89.226,无法在跳板机访问,但可以在node上访问:curl http://172.21.89.226

    LoadBalancer负载均衡,一般阿里云标准用法是EIP绑定到SLB上,通过SLB对外提供服务。SLB创建时选内部SLB,交换机选k8s-node使用的,比如IP是172.17.232.159。然后再买EIP绑定到SLB。不用创建SLB侦听,k8s会自动做这事,创建后是这样:

    $ kubectl get svc/nginx-service
    NAME            TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)        AGE
    nginx-service   LoadBalancer   172.21.113.176   172.17.232.159   80:30589/TCP   6s
    

    可以发现,类型是LoadBalancer,设置了ExternalIP。

    Service Discovery

    服务发现可以用ENV环境变量,或者DNS。

    当注册Service后,K8S会在POD启动时,增加服务对应的环境变量,那么POD就可以用这个环境变量来发现服务了。

    CoreDNS组件开启后,创建了Service就会创建对应ServiceName的DNS记录,比如nginx-service。

    $ kubectl get service/nginx-service
    NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    nginx-service   ClusterIP   172.21.7.190   <none>        80/TCP    16m
    
    $ kubectl exec srs3-demo-deploy-55df684cbb-5dzsh -- ping nginx-service
    PING nginx-service.default.svc.cluster.local (172.21.7.190) 56(84) bytes of data.
    64 bytes from nginx-service.default.svc.cluster.local (172.21.7.190): icmp_seq=1 ttl=64 time=0.033 ms
    

    StatefulSets时,需要给每个Pod分配可达的地址,这就是HeadlessServices。通过配置:ClusterIP: None 来指定的。

    声明式更新

    Declarative updates,声明式更新:

    However, a Deployment is a higher-level concept that manages 
    ReplicaSets and provides declarative updates to Pods along with 
    a lot of other useful features.
    

    这文章说declarative updates

    1. kubectl apply一般是declarative。参考#1#2
    2. kubectl run会转成declaratively Deployment:kubectl translates your imperative command into a declarative Kubernetes Deployment object. A Deployment is a higher-level API that allows rolling updates (see below).
    3. 意味着保持期望状态和实际状态一致:The Kubernetes API is fundamentally declarative, which means that the controllers always work to reconcile the observed state with the desired state. Therefore, if we delete a Pod, the ReplicaSet controller will create a new one to replace it, to maintain the desired replica count.
    4. 配置你想要的,K8S知道怎么实现:However, the power of Kubernetes is in its declarative API and controllers. You can just tell Kubernetes what you want, and it will know what to do.
    5. apply是幂等操作,可以执行多次:The kubectl apply command is idempotent. We can reuse it after modifying the manifests.

    官方也有几个文章说Imperative命令式和Declarative声明式:

    Aliyun ACK

    ACK托管集群,需要的基本资源:

    • 至少1个worker,2CPU2GB。包括,Replicas:10个,内存:850m,CPU:1030Mi。
    • 虽然coredns是两个replicas,但是也可以运行在一个worker上面。
    • 至少3个IP,1个是kubectl访问集群用,1个是SLB对外提供服务用,1个是绑定到worker访问外网用(比如下载更新docker镜像)。

    相关文章

      网友评论

          本文标题:K8S备忘录

          本文链接:https://www.haomeiwen.com/subject/vytfqltx.html