Docker

Docker比较虚拟机

传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

Docker的本质

Docker容器本质上是宿主机上的进程。Docker 通过namespace实现了资源隔离,通过cgroups实现资源限制,通过写时复制机制(Copy-on-write)实现了高效的文件操作。

/* 定义一个给 clone 用的栈,栈大小1M */
#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};


int container_main(void* arg)
{
    printf("容器进程[%5d] ----进入容器!\n",getpid());
    mount("proc", "/proc", "proc", 0, NULL);
    /**执行/bin/bash */
    execv(container_args[0], container_args);
    printf("出错啦!\n");
    return 1;
}

int main()
{
    printf("宿主机进程[%5d] - 开始一个容器!\n",getpid());
    /* 调用clone函数 */
    int container_pid = clone(container_main, container_stack+STACK_SIZE,  CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL);
    /* 等待子进程结束 */
    waitpid(container_pid, NULL, 0);
    printf("宿主机 - 容器结束!\n");
    return 0;
}

Docker容器有几种状态

四种状态:运行、已暂停、重新启动、已退出。

Docker数据卷的作用

数据卷是存在于一个或多个容器中的特定的目录,这一目录绕过UFS,可以提供以下特性:

  1. 数据卷可以在容器之间共享和重用;
  2. 对数据卷的修改会立马生效;
  3. 对数据卷的更新,不会影响镜像;
  4. 数据卷是被设计用来持久化数据的,它的生命周期独立于容器,默认会一直存在,即使容器被删除。

namespace资源隔离

一般,Docker容器需要并且Linux内核也提供了这6种资源的namespace的隔离:

  1. UTS : 主机与域名
  2. IPC : 信号量、消息队列和共享内存
  3. PID : 进程编号
  4. NETWORK : 网络设备、网络栈、端口等
  5. Mount : 挂载点(文件系统),类似chroot
  6. User : 用户和用户组
  • Pid namespace

用户进程是lxc-start进程的子进程,不同用户的进程就是通过pid namespace隔离开的,且不同namespace中可以有相同PID,具有以下特征: 1、每个namespace中的pid是有自己的pid=1的进程(类似/sbin/init进程) 2、每个namespace中的进程只能影响自己的同一个namespace或子namespace中的进程 3、因为/proc包含正在运行的进程,因此而container中的pseudo-filesystem的/proc目录只能看到自己namespace中的进程 4、因为namespace允许嵌套,父进程可以影响子namespace进程,所以子namespace的进程可以在父namespace中看到,但是具有不同的pid

  • Net namespace

有了pid namespace ,每个namespace中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过netnamespace实现的, 每个net namespace有独立的network devices, IP address, IP routing tables, /proc/net目录,这样每个container的网络就能隔离开来, LXC在此基础上有5种网络类型,docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge连接在一起

  • IPC namespace Container中进程交互还是采用linux常见的进程间交互方法(interprocess communication-IPC)包括常见的信号量、消息队列、内存共享。然而同VM不同, container的进程交互实际是host具有相同pid namespace中的进程间交互,因此需要在IPC资源申请时加入namespace信息,每个IPC资源有一个唯一的32bit ID
  • Mnt namespace 类似chroot ,将一个进程放到一个特定的目录执行,mnt namespace允许不同namespace的进程看到的文件结构不同,这样每个namespace中的进程所看到的文件目录被隔离开了,同chroot不同,每个namespace中的container在/proc/mounts的信息只包含所在namespace 的mount point
  • Uts namespace UTS(UNIX Time sharing System)namespace允许每个container拥有独立地hostname和domain name,使其在网络上被视作一个独立的节点而非Host上的一个进程
  • User namespace 每个container可以有不同的user和group id ,也就是说可以container内部的用户在container内部执行程序而非 Host上的用户

cgroups资源隔离

cgroups提供了以下四大功能:

  1. 资源限制: 可以对任务使用的资源的总额进行限制。如设定应用运行时使用内存的上限,一旦超过这个配额就发出OOM(Out of memory)提示。
  2. 优先级分配 :通过分配的CPU时间片数量及磁盘IO带宽大小,实际上就相当于控制了任务运行的优先级。
  3. 资源统计:cgroups可以统计系统的资源使用量,如CPU使用时长、内存用量等,这个功能非常适用于计费。
  4. 任务控制: cgroups可以对任务执行挂起、恢复等操作。

K8s

K8s具体功能:

  • 自动化容器部署和复制。
  • 实时弹性收缩容器规模。
  • 容器编排成组,并提供容器间的负载均衡。
  • 调度:容器在哪个机器上运行。

k8s基础组件有哪些,什么功能

master组件
kube-apiserver

集群的核心,负责各个功能模块之间的通信。各个模块都通过apiserver将信息存入etcd。

kube-controller-manager

控制器有很多种,通过 apiserver 监控整个集群的状态,确保集群始终处于预期的工作状态。

kube-scheduler

负责调度,将pod调度到最优节点上。

etcd

存储kubernetes的元数据,高可用。

node组件
kubelet

每个节点上运行的代理,确保容器处于运行状态且健康。会定期想master汇报资源使用情况。

一个pod创建流程

可通过kubectl或yaml创建pod请求

apiserver接收到请求后,会存储pod数据到etcd

scheduler的watch接口会从apiserver处监听到新建pod的信息,scheduler会根据集群的整体信息,选出最优的node进行调度,会通过apiserver将信息写到etcd里

目标node上的kubelet通过apiserver监听到新建的pod,会去调用Container Runtime Interface (CRI) 创建相应pod.

(kube-controller-manager 会确保pod处于预期的状态)

pod中pending状态,是什么原因产生的,pod出现问题,排查思路

pending原因

节点资源不足

不满足 nodeSelector 与 affinity

Node 存在 Pod 没有容忍的污点

kube-scheduler 未正常运行

镜像不存在

排查思路

kubectl describe pod 查看具体信息

到相应node上查看具体日志

k8s的pause容器有什么用。是否可以去掉

为pod中的多个容器提供共享网络空间,实现pod里容器间的通信。

主要有两个职责:

  1. 是pod里其他容器共享Linux namespace的基础
  2. 扮演PID 1的角色,负责处理僵尸进程

k8s的service和ep是如何关联和相互影响的

service中有selector时才会创建endpoints.

kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。

只要服务中的pod集合发生更改,endpoints就会被更新。

详述kube-proxy原理

监听 API server 中 service 和 endpoint 的变化情况,并通过 iptables 等来为服务配置负载均衡

kube-proxy的作用主要是负责service的实现

service另外一个重要作用是,一个服务后端的Pods可能会随着生存灭亡而发生IP的改变,service的出现,给服务提供了一个固定的IP,而无视后端Endpoint的变化。

kube-proxy 模式

  • userspace 已弃用。该模式请求在到达 iptables 进行处理时就会进入内核,而 kube-proxy 监听则是在用户态, 请求就形成了从用户态到内核态再返回到用户态的传递过程, 一定程度降低了服务性能。
  • iptables 大规模下会有性能问题 且不支持会话保持
  • ipvs

kubernetes发布策略(4种)

  • Recreate 在创建出新的Pod之前会先杀掉所有已存在的Pod
  • RollingUpdate 滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本Pod。deployment支持版本升级过程中的暂停、继续功能以及版本回退等诸多功能
  • 蓝绿发布
  • 灰度发布(金丝雀发布) 比如有一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。