1. go语言

《Go程序设计语言》、《the way to go》

2. Docker

2.1 Dockerfile

命令 格式 说明
FROM FROM : 指定基础镜像(scratch/ubuntu…)
COPY COPY 复制本地文件到镜像
ADD ADD 复制本地文件或网络文件的url到镜像
ENV ENV = 为镜像创建出的容器声明环境变量
ARG ARG = 设置构建环境的变量,在容器运行是不存在。
WORKDIR WORKDIR <工作目录> 指定工作目录
RUN RUN 以上一条指令创建的镜像创建容器,并在容器中运行命令,命令结束后提交为新镜像,并被下一条执行使用
RUN [“executable”, “param1”, “param2”]
CMD CMD 提供容器运行时的默认值;
Dockerfile中可以有多条CMD指令,但只有最后一条有效;
docker run指令中的参数会覆盖CMD的指令;
CMD [“executable”, “param1”, “param2”]
CMD [“param1”, “param2”]
(为ENTRYPOINT指令提供参数)
ENTRYPOINT ENTRYPOINT 提供容器运行时的默认值;
Dockerfile中可以有多条ENTRYPOINT指令,但只有最后一条有效;
当使用shell格式时,ENTRYPOINT指令会忽略docker run中的参数和CMD的指令,并运行在bin/sh –c中;
exec格式(推荐),docker run 传入的命令参数会覆盖CMD指令的内容并附加到ENTRYPOINT指令的参数中;
ENTRYPOINT [”executable”, “param1”,”param2”]
VOLUME VOLUME [“path1”, “path2”…] 定义匿名卷,可在docker run指令中指定数据卷以覆盖匿名卷
VOLUME
EXPOSE EXPOSE …] 声明端口,只是声明;
方便镜像使用者理解、docker run –P 命令自动随机映射端口;

2.2 多阶段构建

多个镜像构建过程写一个Dockerfile文件。

2.3 打包

镜像 docker save
docker load
容器 docker export
docker import

2.4 镜像

2.4.1 镜像特点

1)分层
镜像由一系列镜像层组成,镜像层分为只读层和读写层。分层使不同镜像之间共享镜像层,使docker镜像轻量。
2)写时复制
Copy-On-Write策略,使多个容器之间可以共享镜像。每个容器启动时,将所有镜像层挂载到一个挂载点,再覆盖一个可读写的容器层。减少磁盘占用和容器启动时间。
3)内容寻址
根据文件内容来索引(sha256哈希值)镜像和镜像层,最为镜像层的唯一标志。
4)联合挂载
联合挂载技术:在一个挂载点同时挂载多个文件系统,整合挂载内容,使得最终可见的的文件系统包含各层文件和目录。
联合文件系统(union filesystem):实现联合挂载技术的文件系统。

联合挂载,用于将多个镜像层的文件系统挂载到一个挂载点来实现一个统一文件系统。

2.4.2 镜像元数据

2.4.2.1 registry
registry用于保存Docker镜像,其中还包括镜像层次结构和关于镜像的元数据。Docker从registry中下载镜像保存在宿主机上,然后启动容器。

1)公有registry
Docker Hub:Docker官方维护的公共仓库;
阿里云docker仓库
2)私有registry
Docker Registry:官方提供的工具,用于构建私有的镜像仓库;
Docker Harbor:an open source trusted cloud native registry project that stores, sings, and scans content. 一般作为企业级Registry服务;

2.4.2.2 repository
repository是由具有某个功能的Docker镜像的所有迭代版本构成的镜像组。

registry是repository的集合,repository是image的集合。

2.4.2.3 manifest
manifest(描述文件),存在于registry中作为镜像的元数据文件。镜像被pull到宿主机时,自动转化为镜像配置文件。
2.4.2.4 image/layer
image:存储镜像相关的元数据信息;
layer:镜像层;

2.4.3 仓库

参考1.4.2.1 registry 章节

2.5 数据卷

  1. 为什么使用数据卷?
  • 联合挂载导致容器中的文件在宿主机上存在形式复杂,不能方便的对容器中的文件访问;
  • 多个容器之间的数据无法共享;
  • 删除容器时,数据丢失;
  1. 什么是数据卷?
    数据卷(Volume):存在于一个或多个容器中的特定文件或文件夹,存在于宿主机上,并为数据的共享和持久化提供便利。
  • 容器创建时初始化,运行时可使用文件;
  • 容器间共享;
  • 持久化;
  1. 数据卷的使用
  • docker volume 命令;
  • 共享volume(--volumes-from参数与已有容器共享volume);
  • Dockfile 中的匿名数据卷;

2.6 Docker网络管理

2.6.1 libnetwork网络库

Docker daemon 通过调用libnetwork网络库的API完成网络的创建和管理等功能。

  • 端点:一个端点只属于一个网络,并且只属于一个沙盒,端点的实现可以是veth pair、Open vSwitch内部端口或者相似设备;
  • 网络:一个网络是一组可以直接互相连通的端点;
  • 沙盒:一个沙盒可以有多个端点和多个网络;

libnetwork实现了5种内置驱动,以bridge/host 驱动为例:

  • bridge driver:Docker的默认驱动,容器连接到Docker网桥(Docker0)上,与外界通信需要使用NAT(network address translation, 网络地址转换);
  • host driver:容器不进行network namespace网络隔离,容器中的进程处于宿主机的网络环境,使用宿主机的网卡、ip和端口。host模式解决了容器与外界通信的地址转换,可以直接使用宿主机的IP。

2.6.2 docker network 命令

$ docker network -h
Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

2.6.3 iptables

// TODO

2.7 Docker背后的内核知识

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

2.7.1 namespace 资源隔离

linux内核实现namespace的一个主要目的,就是实现轻量级虚拟化服务。在同一个namespace下的进程可以感知彼此的变化,而对外界的进程一无所知。这样就可以让容器中的进程产生错觉,仿佛置身于一个独立的系统环境中,以达到独立和隔离的目的。

namespace的6项隔离
namespace 系统调用参数 隔离内容
UTS CLONE_NEWUTS 主机名与域名
IPC CLONE_NEWIPC 信号量、消息队列、共享内存
PID CLONE_NEWPID 进程编号
Network CLONE_NEWNET 网络设备、网络栈、端口等
Mount CLONE_NEWNS 挂载点(文件系统根目录)
User CLONE_NEWUSER 用户和用户组

2.7.2 cgroups 资源限制

cgroups是linux内核提供的一种机制,可以根据需求把一系列系统任务及其子任务按资源划分等级的不同组内,从未为系统资源管理提供一个统一的框架。
cgroups限制、记录任务组所使用的物理资源(CPU、Memory、IO),为容器实现虚拟化提供了基本保证,是构建Docker等一系列虚拟化管理工具的基石。

3. kubernetes

3.1 什么是kubernetes

Kubernetes脱胎于Google的大规模集群管理工具Borg,管理跨主机Docker容器,实现了应用部署、高可用管理和弹性伸缩功能,并封装了一套RESTful API对外提供服务。
Kubernetes设计哲学之一,维护应用容器集群一直处于用户所期望的状态。

3.2 核心概念

3.2.1 pod

kubernetes中,能够被创建、调度和管理的最小单元是pod,而非单个容器。一个pod是由若干个Docker容器构成的容器组(pod意为豆荚,容纳多个豆子,很形象)。
同一个pod中的容器有两个特性:
  • 通过kubernetes volume机制,在容器间共享存储;
  • 通过localhost直接访问另一个容器;

3.2.2 label 和 label selector

当系统运行着大量的pod时,用户如何有效的定位与组织这些pod?kubernetes的解决方案是label。每个pod都一个属性“labels”:
“labels”:{

“key1”:”value1”,

“key2”:”value2”

}
$ kubectl get pods –n root –l name=nginx
kubernetes中的其他对象,如deployment、service,同样可以根据label对pod进行定位和组织。
在kubernetes中,label是一种重要的且被广泛应用的组织、分类和选择kubernetes对象的机制。
  • labels属性是一组绑定到kubernetes对象(如pod)上的键值对,同一个对象labels属性的key必须独一无二。
  • label不直接作为系统内部唯一标识kubernetes对象的依据,因为不同于对象名和uuid,label并不保证唯一性。
    label selector 是kubernetes核心的分组机制,通过label selector 能够识别一组有共同属性的kubernetes对象。有两种label selector 查询条件:
  • 基于值相等的查询条件;= !=
  • 基于子集的查询条件;in notin

3.2.3 replication controller

replication controller(副本控制器)决定了一个pod有多少个同时运行的副本,并保证这些副本的当前状态与期望状态一致。
RC的典型场景:
  • 重调度。当pod异常,kubernetes会进行相应pod重调度;
  • 弹性伸缩。手动或自动修改副本数replicas字段;
  • 滚动更新(灰度发布)。逐个替换pod进行更新;
  • 多版本release追踪。利用labels 和 label selector 机制;

replica set
新一代副本控制器,也是用于保证与label selector匹配的pod数量维持在期望状态。
replica set和replication controller 区别在于:replication controller 仅支持基于值相等的selector查询,replica set引入了基于子集的selector查询条件;

Deployment
Deployment用于 为pod和replica set提供更新,并可以方便的跟踪观察其所属的replica set 或者 pod 数量以及状态的变化。即,deployment是为了应用的更新而设计的。

3.2.4 service

为什么需要service?

  • 由于重调度,pod在kubernetes中的IP地址不是固定的,因此需要一个代理来确保需要使用pod的应用不需要知晓pod的真实ip地址;
  • 当使用RC创建多个pod的副本时,需要一个代理来为pod做负载均衡;

什么是service?
service主要由一个固定IP地址和一个label selector组成。通过创建service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并将请求进行负载均衡到后端的各个容器应用上。

如何定义一个service?

  1. 代理一个pod集 前提:有一个pod集,其中的所有pod均被贴上一个相同的labels:{“app”:”nginx”},且所有容器均对外暴露一个端口8080; service对象的配置信息:指定后端服务的”selector”,”ports”属性。
“spec”:{

“selector”:{

“app”:”nginx”

},

“ports”:[

{

“protocol”:”TCP”,

“port”:80,

“targetPort”:8080

}

]

}
  1. 该service会将外部流量转发到所有匹配selector的pod的targetPort端口上;
    service的入口地址:系统分配一个虚拟IP+port端口,也可以在配置信息spec.clusterIP字段手动指定service的虚拟IP;
    当service对象被创建后,系统会随之创建一个同名的Endpoints对象,保存了所有匹配label selector的后端pod的IP和端口;
  2. 代理外部服务
    外部服务没有labels属性,service也就没有label selector,系统也不会自动创建Endpoints对象,显式的将service映射到一个或多个后端服务(外部服务)。

3.2.5 Pod、RC、Service之间的关系

Pod、RC、Service的关系图

3.3 kubectl 集群管理工具

3.4 yaml文件语法

3.5 应用实例

通过实例学习一下操作:

  1. Pod 创建,内存,CPU限制
    2 V, PV,PVC
  2. Service,deployment 创建
    4 AutoScale
    3.5.1 nginx
    nginx实例
    3.5.2 redis
    k8s上使用StatefulSet进行Redis集群的部署

3.6 kubernetes各大组件

APIServer
APIServer负责对外提供kubernetes API 服务,作为系统管理指令的统一入口,统揽全局,任何对资源进行ACID操作都交个APIServer处理后才能提交给etcd。
scheduler
scheduler 根据特定的调度算法将pod调度到指定的工作节点上(即绑定bind)。

controller manager
controller manager 管理集中的各种控制器(如replication controller、node controller),负责控制管理对应的资源,确保资源保持在用于预期的状态。
kubelet
kubelet是kubernetes集群的工作节点上最为重要的组件进程,负责管理和维护在这台主机上运行着的所有容器,使得pod的运行状态status与期望值spec一致。
kube-proxy
kube-proxy是kubernetes服务发现和反向代理服务的底层实现。
服务发现:kube-proxy使用etcd的watch机制,监控集群中service和endpint对象数据的动态变化,并维护一个从service到endpoint的映射关系,从而保证了后端pod的ip变化不会对访问者造成影响。
方向代理:kube-proxy支持TCP/UDP连接转发,默认使用Round Robin算法(依次从可用工作节点列表中选取一个工作节点)将流量转发到与service对应的一组后端pod。

3.7 各大组件协作

创建pod

创建RC

创建service