• 深入剖析Kubernetes


    (1)PasS: Cloud Foundry,PaaS提供一种应用托管的能力,基于IaaS(Infrastructure as a service)之上
    Docker镜像,使得本地环境和云端环境高度一致

    (2)编排(Orchestration): 主要指用户如何通过某些工具或者配置来完成一组虚拟机以及关联资源的定义,配置,创建,删除等工作,然后由云计算平台按照这些指定的逻辑来完成的过程。
    CNCF: Cloud Native Computing Foundation

    Borg, Omega
    Istio, Operator, Rook

    1.容器技术基础

    1.1.Linux Namespace

    Linux namespace机制:为Linux创建新进程的一个可选参数,调用的为如下方法:

      int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL)
    
    • 1

    除了PID Namespace机制,Linux还提供了Mount,UTS,IPC,Network和User这些namespace,用于对各种不同的进程上下文进行障眼法操作。

    • Mount namespace: 用于让被隔离进程只看到当前namespace里的挂载点信息;
    • Network namespace:用于让被隔离进程看到当前Namespace里的网络设备和配置。

    Docker在创建容器进程时,指定了该进程所需要启动的一组namespace参数,容器只能看到当前namespace所限定的资源,文件,设备,状态,或者配置,容器只是一种特殊的进程而已,而这些进程在namespace的作用下只能看到指定的资源,因此给人一种感觉好像和操作系统隔离了,其实只是缩小了容器所能看见的资源。

    # 容器进入mac虚拟机终端
    screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty
    
    • 1
    • 2

    在这里插入图片描述
    docker engine 更多地扮演旁路由和辅助管理工作。
    在这里插入图片描述

    • 虚拟化技术:采用Hypervisor来负责创建虚拟机,该虚拟机真实存在,并且里面必须运行一个完整的Guest OS才能执行用户的应用进程;且虚拟机本身就需要占用内存,对宿主机操作系统的调用不可避免地要经过虚拟化软件的拦截和处理。

    • 容器化技术:相比于虚拟化技术,隔离的不彻底,多个容器为运行在宿主机上的一种特殊进程,那么多个容器之间使用的就还是同一个宿主机操作系统内核。且在Linux内核中,很多资源和对象是不能被namespace化的。
      如时间,加入你在容器中修改时间,宿主机也会跟着改变。

    针对这种缺点,可以采用Seccomp等技术,对容器内部发起的所有系统调用进行过滤和甄别来进行安全加固,但这种方法因为读了一层对系统调用的过滤,会拖累容器性能。

    1.2.Linux Cgroup

    Linux Control Group 是linux内核中用来为进程设置资源限制的一个重要功能,包括CPU,内存,磁盘,网络带框。
    在Linux中,Cgroups给用户暴露出来的操作接口时文件系统,即它以文件和目录的方式组织在操作系统/sys/fs/cgroup 下

    Cgroup 配置及使用
    (1)挂载使用cgroup
    在这里插入图片描述
    (2)创建一个container目录组,其下会自动生成相关限制文件
    在这里插入图片描述
    (3)创建一个进程用于测试
    在这里插入图片描述
    (4)将上述进程号写入tasks文件中
    修改cpu.cfs_quota_us文件设置cpu使用额度为20ms,意味着限制cpu使用为20%
    在这里插入图片描述
    除了对cpu资源的限制

    • blkio:为块设备设置I/O限制,一般用于磁盘等设备
    • cpuset:为进程分配单独的CPU核和对应的内存节点
    • memory:为进程设定内存使用的限制
      linux cgroups设计比较易用,可以理解为一个子系统目录加上一组资源限制文件的组合。
      我们可以看到该目录下有docker以及kubepod
      在这里插入图片描述
    docker run -it --cpu-period=100000 --cpu-quota=20000 busybox /bin/bash
    
    • 1

    可以看出docker run的容器在对应的目录下都做了cgroup的限制;
    在这里插入图片描述
    在这里插入图片描述
    一个正在运行的Docker容器,其实就是启用了多个Linux Namespace的应用进程,而该进程可以使用的资源量,受到Cgroups配置的限制,容器是一个单进程模型。

    ## ns.c
    #define _GNU_SOURCE
    #include  
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define STACK_SIZE (1024 * 1024)
    static char container_stack[STACK_SIZE];
    char* const container_args[] = {
      "/bin/bash",
      NULL
    };
    
    int container_main(void* arg)
    {  
      printf("Container - inside the container!\n");
      // 如果你的机器的根目录的挂载类型是shared,那必须先重新挂载根目录 // mount("", "/", NULL, MS_PRIVATE, "");     
      mount("none", "/tmp", "tmpfs", 0, "");
    
      execv(container_args[0], container_args);
      printf("Something's wrong!\n");
      return 1;
    }
    
    int main()
    {
      printf("Parent - start a container!\n");
      int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWNS | SIGCHLD , NULL);
      waitpid(container_pid, NULL, 0);
      printf("Parent - container stopped!\n");
      return 0;
    }
    
    • 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
    # 执行上述代码后进入新的容器
    gcc -o ns ns.c 
    ./ns
    # 但发现该容器和宿主机的内容一样
    ls -al
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    经过实践,我们发现通过mount(“none”, “/tmp”, “tmpfs”, 0, “”);可以将指定文件挂载至容器中,从而可以控制容器中的文件;

    mkdir -p ~/test
    mkdir -p ~/test/{bin,lib64,lib}
    cd ~/test
    # 详细显示命令执行的操作
    cp -v /bin/{bash,ls,sh} ~/test/bin
    list="$(ldd /bin/ls | egrep -o '/lib.*\.[0-9]')"
    for i in $list; do mkdir ~/test`dirname $i`; cp -v $i ~/test$i; done
    
    # 改变 /bin/sh 进程的根目录到~/test
    chroot ~/test /bin/sh
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    通常会将挂载在容器根目录上,用来为容器提供隔离后执行环境的文件系统,成为容器镜像,rootfs

    • pivot_root:改变文件系统,将当前进程的root文件系统放在put_old目录下,使得new_root成为新的文件系统
    • chroot:在指定根目录下运行指令

    rootfs是一个操作系统所包含的文件,配置和目录,并不包括操作系统内核,相当于躯体,而linux操作系统内核是操作系统的灵魂,所有容器共享同一个linux内核,意味着该内核的修改会影响所有容器;

    Docker在镜像的设计中,引入了层的概念,即用户制作镜像的每一步操作都会生成一个层,为增量的rootfs

    • Union File System: 将多个不同位置的目录联合挂载到同一个目录下
    # 将./B, ./A, ./C 联合挂载到./D 中,文件覆盖规则如下图
    mkdir A
    echo aa > ./A/a
    echo xx > ./A/x
    mkdir B
    echo bbb > ./B/b
    echo xxx > ./B/x
    mkdir BB
    echo bbbbbb > ./BB/b
    echo xxxxxx > ./BB/x
    mkdir C
    mkdir D
    # 其中./A为最上层,./BB为第二层,./B为第三层
    # 原理:挂载时,会将低级目录文件全部拷贝到上级目录中,因此对低级目录中的文件修改并不会修改原本的文件
    mount -t overlay overlay -o lowerdir=./BB:./B,upperdir=./A,workdir=./C ./D
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述
    可以看出docker使用的是overlay2的方式进行文件的联合挂载
    在这里插入图片描述

    docker pull nginx
    docker inspect nginx
    root@raspberrypi:~# docker inspect nginx
    [
        {
            "Id": "sha256:b7dd3d7d83385d0bad882b2a2e1298d2c2003dd58eeae7d959e183b8d8392b9b",
            "RepoTags": [
                "nginx:latest"
            ],
            "RepoDigests": [
                "nginx@sha256:790711e34858c9b0741edffef6ed3d8199d8faa33f2870dea5db70f16384df79"
            ],
            "Parent": "",
            "Comment": "",
            "Created": "2022-08-03T20:11:32.842853023Z",
            "Container": "a562c0d94e0989705c34428ecc49bc8cf0339b71469f2574ce156593e1e05368",
            "ContainerConfig": {
                "Hostname": "a562c0d94e09",
                "Domainname": "",
                "User": "",
                "AttachStdin": false,
                "AttachStdout": false,
                "AttachStderr": false,
                "ExposedPorts": {
                    "80/tcp": {}
                },
                "Tty": false,
                "OpenStdin": false,
                "StdinOnce": false,
                "Env": [
                    "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                    "NGINX_VERSION=1.23.1",
                    "NJS_VERSION=0.7.6",
                    "PKG_RELEASE=1~bullseye"
                ],
                "Cmd": [
                    "/bin/sh",
                    "-c",
                    "#(nop) ",
                    "CMD [\"nginx\" \"-g\" \"daemon off;\"]"
                ],
                "Image": "sha256:8a3bbfa267ceda280efc568b8faa75fde2761c14607d20256d73b1a390188daa",
                "Volumes": null,
                "WorkingDir": "",
                "Entrypoint": [
                    "/docker-entrypoint.sh"
                ],
                "OnBuild": null,
                "Labels": {
                    "maintainer": "NGINX Docker Maintainers "
                },
                "StopSignal": "SIGQUIT"
            },
            "DockerVersion": "20.10.12",
            "Author": "",
            "Config": {
                "Hostname": "",
                "Domainname": "",
                "User": "",
                "AttachStdin": false,
                "AttachStdout": false,
                "AttachStderr": false,
                "ExposedPorts": {
                    "80/tcp": {}
                },
                "Tty": false,
                "OpenStdin": false,
                "StdinOnce": false,
                "Env": [
                    "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                    "NGINX_VERSION=1.23.1",
                    "NJS_VERSION=0.7.6",
                    "PKG_RELEASE=1~bullseye"
                ],
                "Cmd": [
                    "nginx",
                    "-g",
                    "daemon off;"
                ],
                "Image": "sha256:8a3bbfa267ceda280efc568b8faa75fde2761c14607d20256d73b1a390188daa",
                "Volumes": null,
                "WorkingDir": "",
                "Entrypoint": [
                    "/docker-entrypoint.sh"
                ],
                "OnBuild": null,
                "Labels": {
                    "maintainer": "NGINX Docker Maintainers "
                },
                "StopSignal": "SIGQUIT"
            },
            "Architecture": "arm",
            "Variant": "v7",
            "Os": "linux",
            "Size": 109131098,
            "VirtualSize": 109131098,
            "GraphDriver": {
                "Data": {
                    "LowerDir": "/var/lib/docker/overlay2/3e8262849af4cbc4cde895685870114127ffd57eead9416c928784291f4ba53f/diff:/var/lib/docker/overlay2/e277a2e14d5ba7c3c7edfb746bb8e074f6bdd96fb0427a8d520e2efd4b9e43c9/diff:/var/lib/docker/overlay2/a05ffd4fecc6c4e32ed65ab5a88c4214969b88b152dab7612dd28ef1b4ebc704/diff:/var/lib/docker/overlay2/dd7005f61f9f06554ab770992ac1463727a7cd79398cde359ba5795fb381eb48/diff:/var/lib/docker/overlay2/a471495d68abb4636ca1414d1cf5e5fcd8241df8d82c4c24a8931f25d0f70ac9/diff",
                    "MergedDir": "/var/lib/docker/overlay2/670fa195d32249e3ba78bf989417dcf09272b0f5a950b3edcfb82fdf2d9f02de/merged",
                    "UpperDir": "/var/lib/docker/overlay2/670fa195d32249e3ba78bf989417dcf09272b0f5a950b3edcfb82fdf2d9f02de/diff",
                    "WorkDir": "/var/lib/docker/overlay2/670fa195d32249e3ba78bf989417dcf09272b0f5a950b3edcfb82fdf2d9f02de/work"
                },
                "Name": "overlay2"
            },
            "RootFS": {
                "Type": "layers",
                "Layers": [
                    "sha256:ddffee9f8d11b7acf1e1f7b78d0ec21b79d51a283a3fdaf10fd4d13d14693648",
                    "sha256:29110869bb9fdb3ebf6da2f4297c36cb3bd8733fdbe5bb33bfe6d77745640d3d",
                    "sha256:b3c88d2b26a3f1920c90dea050fa4478d71b9ccf7a6b1eea601e4f369ec52132",
                    "sha256:51d4212bec0900e2747c5c7ca68777922ec775dcd3b462c0e279b1c519195bec",
                    "sha256:54c0a6219829bca9912b9ac604b110af109a0a876c57b4716a9a68ed662dca5d",
                    "sha256:e44bd7094faabcc9f4e6c77e635a98a586affa70b7c36f0709848c60fc858d58"
                ]
            },
            "Metadata": {
                "LastTagTime": "0001-01-01T00:00:00Z"
            }
        }
    ]
    
    • 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
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121

    如上RootFS显示,ngnix由6层组成。
    可以看出该文件为一个完整linux目录结构
    在这里插入图片描述
    如果自己对容器中文件进行修改后,会产生新的层,此时我们docker commit; docker push 即可生成自己的容器。
    docker 支持的UnionFS: aufs, device, mapper, btrfs, overlayfs, vfs, zfs。

    在这里插入图片描述

    在这里插入图片描述
    控制节点:包含kube-apiserver, kube-schedule, kube-controller-manager,集群中持久化数据由kube-apiserver处理后保存在etcd中。

    Device Plugin: k8s用于管理GPU等宿主机物理设备的主要组件;
    OCI(Open Container Interface),为CRI的一个标准,使用linux内核系统调用。
    CRI(Container Runtime Interface):按标准容器运行镜像,docker为其中一个实现。
    CNI(Container Network Interface):网络插件
    CSI(Container Storage Interface):存储插件

    Service服务的主要作用,是作为Pod的代理入口(Portal),从而代替Pod对外暴露一个固定的网络地址。
    在这里插入图片描述
    ipvs模式下,可为Service指定负载均衡策略
    IPVS 提供了更多选项来平衡后端 Pod 的流量。 这些是:

    K8s ipvs Service LoadBalancer

    名称解释
    rr轮替(Round-Robin)
    lc最少链接(Least Connection),即打开链接数量最少者优先
    dh目标地址哈希(Destination Hashing)
    sh源地址哈希(Source Hashing)
    sed最短预期延迟(Shortest Expected Delay)
    nq从不排队(Never Queue)

    声明式API
    容器:容器运行时 + 容器镜像

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.7.9
            ports:
            - containerPort: 80
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    Kubernetes集群搭建与实践

    容器编排与Kubernetes核心特性剖析

    Kuernetes开源社区与生态

  • 相关阅读:
    抽象工厂模式-C++实现
    mysql存储过程和函数
    听GPT 讲Istio源代码--cni
    HMTL知识点系列(1)
    场景应用:键盘敲入字母a时,期间发生了什么?
    内核概述及配置编译
    对于L1正则化和L2正则化的理解
    【3D图像分割】基于 Pytorch 的 VNet 3D 图像分割3(3D UNet 模型篇)
    Kotlin读书总结之面向对象
    【Kubernetes】Pod——k8s中最重要的对象之一
  • 原文地址:https://blog.csdn.net/Yuan_xii/article/details/126311729