1. 概念
1.1. 比较主流的任务编排系统有mesos+marathon,swarm,openshift(红帽内部叫atom服务器)和最著名的kubernetes,居然说yarn也行,不过没见过谁用
1.2. 官方网站 https://kubernetes.io/(需要科学上网)
1.3. 软件架构图
1.4. 每个组件的作用:https://kubernetes.io/docs/concepts/overview/components/
Master Components:主节点组件提供集群的控制功能。他从整体的角度去决定集群应该怎么运行(例如计划任务),并且探测和回应集群的要求(当一个复制节点的“复制请求”失败的时候,他会去启动一个新的pod)
主节点组建可以运行在集群中的任意一台机器。但是,简单来说,创建脚本只能在一台机器上启动所有的主要组件,但是不能在这台机器上启动用户容器。
kube-apiserver:运行在主节点上,用来暴露Kubernetes接口的组建。他在Kubernetes控制面板的前端。他被用来设计成水平扩展,这就是说,他可以扩展成更多的实例。
etcd:一致性和高可用键值存储,用来作为kubernetes集群的后端存储,为你的kubernetes集群准备一个备份计划,用来备份etcd的数据。
kube-scheduler:主节点上的组件,用来观察新创建的,还没有被分配节点的pods,为他们选择一个节点并运行他们。
这需要考虑到个人计划和整体资源的需求,硬件/软件/策略约束,松耦合和解耦,数据本地化,内部负载均衡和结束时间等因素
kube-controller-manager:在主节点上用来运行控制器的。逻辑上来说,每个控制器都是一个独立的进程,但是为了减少复杂性,他们都被编译进了一个二进制文件并且以独立的进程来运行。
Node Controller: 用来通知和响应哪个节点挂掉了
Replication Controller: 为每个副本控制对象服务,负责维护正确的pods数量
Endpoints Controller: 寄宿在终端对象,例如加入service以及pods
Service Account & Token Controllers: 为新的用户空间创建默认用户和接口访问令牌
cloud-controller-manager:云控制器作用在云服务的底层。云控制器在kubernetes1.6中是一个测试版本。云控制器只能跑在特定云服务控制器循环上。
我们可以在 kube-controller-manager.禁止这些控制的循环。我们可以通过在启动 kube-controller-manager设置--cloud-provider选项来关闭它
云控制器允许云供应商二次开发,并且kubernetes核心可以发展成为彼此独立的版本。
在早期的版本,kubernetes核心代码是依赖于cloud-provider-specific的,在未来的版本,特定的为云供应商提供的服务的代码应该都有云供应商自己服务,并且在运行kubernetes的时候连接到cloud-controller-manager
以下的控制器有独立的云提供者
Node Controller: 查询云服务提供者,决定一个节点是否停止响应之后是否还能够被检测到
Route Controller: 在云架构的底层建立起路由
Service Controller: 建立,升级和删除云服务提供者的负载均衡
Volume Controller: 创建,附加和挂载卷组,并且和云服务提供者交互去编排卷组
Node Components:节点组建需要在每个节点上运行,维护工作中的pod并且提供Kubernetes的运行环境
kubelet:在集群上的每个节点都要运行。他能保证每个pod上都有一个container运行,kubelet接管各种机器提供的PodSpecs并且确保这些在PodSpecs中注册的容器健康运行。kubelet不负责那些不是Kubernetes创建的容器
kube-proxy:kube-proxy保证宿主机Kubernetes服务被网络规则抽象管理并且实行连接转发
Container Runtime:运行时容器是负责运行中的容器。kubernetes支持多种运行时容器:Docker,rkt(CoreOS),runc和任何符合OCI(Open Container Initiative)运行时标准的容器
Addons:其他插件是实现集群功能的pods和services。pods可能被部署,副本管理器等组件管理。名称空间插件在kube-system名称空间被创建
DNS:其他的插件都不是严格需要的,但是所有kubenetes集群都必须拥有一个集群的DNS,因为集群非常依赖他
集群DNS是一个dns服务器,作为您其他DNS服务器中的附加服务器,为kubernetes服务器提供DNS记录
containers是由kubenetes搜索DNS之后自动启动的,包括这个DNS服务
Web UI (Dashboard):Dashboard是一个统一管理,为了kubernets集群而准备的网络界面,他运行用户对集群的应用管理和排错,就好像在操作集群一样
Container Resource Monitoring:容器资源监控继续在中心数据库记录创建容器的时间序列,并且提供UI以供浏览这些数据
Cluster-level Logging:集群级别的日志机制是负责保存容器日志的,他可以集中存储日志,并提供搜索和浏览的接口
1.5. Policy Layer: API Server:
API server是一个策略组件,提供对Etcd的过滤访问。它的作用本质上是相对通用的,目前正在被分解处理。因此,API Server也可以用于其他系统的控制平面。
API server的主要货物是资源,通过暴露简单的REST API 向外提供服务。这些资源有一个标准结构可以实现一些扩展功能。无论如何,API Server,允许各类组件创建,读取,写入,更新,和监视资源。
API Server的具体的功能:
•认证和授权。Kubernetes有一个可插拔的认证系统。有一些内置的用户认证机制和授权这些用户访问资源。此外,还有一些方法可用于向外部服务提供这些服务。这种可扩展性是Kubernetes构建的核心功能。
•API Server运行一组可以拒绝或修改请求的准入控制器。 这些允许策略被应用并设置默认值。 这是确保在API Server客户端仍在等待请求确认时进入系统的数据有效性的关键。 虽然这些准入控制器目前正在编译到API Server中,但目前正在进行的工作是使其成为另一种可扩展性机制。
•API Server 有助于API 版本控制。API 版本的一个关键问题是允许资源的字段的改变,字段添加,弃用,重新组织和以其他方式转换。 API Server在Etcd中存储资源的"true"表示,并根据满足的API版本转换/呈现该资源。 自项目早期开始,规划版本控制和API的发展一直是Kubernetes的一项重要工作。
•API Server 一个重要特性是支持watch机制。这意味着API Server的客户端可以使用与Etcd相同的协调模式。Kubernetes中的大多数协调包括写入另一个组件正在监视的API服务器资源的组件。 第二个组件将对几乎立即发生的变化做出反应。
1.6. 业务逻辑:Controller Manager and Scheduler
这些是通过API Server 进行协调的组件。这些称为Controller Manager和Scheduler的组件绑定到单独的服务器Master上
Scheduler组件将做许多事情让系统工作:
1.查找未分配给节点的Pod(未绑定的Pod);
2.检查集群的状态(缓存在内存中);
3.选择具有空闲空间并满足其他约束条件的节点;
4.将pod绑定到该节点。
Controller Manager 组件,实现ReplicaSet的行为。(ReplicaSet可以确保任何时候都可以运行一个Pod模板的副本数量)。控制器将根据资源中的选择器 监控ReplicaSet 资源和一组Pod。为了保持在ReplicaSet中稳定的一组Pod,控制器将创建、销毁Pod。
1.7. 一次请求:
这个时序图展示了创建pod的流程,基本的流程如下:
1. 用户提交创建Pod的请求,可以通过API Server的REST API ,也可用Kubectl命令行工具,支持Json和Yaml两种格式;
2. API Server 处理用户请求,存储Pod数据到Etcd;
3. Schedule通过和 API Server的watch机制,查看到新的pod,尝试为Pod绑定Node;
4. 过滤主机:调度器用一组规则过滤掉不符合要求的主机,比如Pod指定了所需要的资源,那么就要过滤掉资源不够的主机;
5. 主机打分:对第一步筛选出的符合要求的主机进行打分,在主机打分阶段,调度器会考虑一些整体优化策略,比如把一个Replication Controller的副本分布到不同的主机上,使用最低负载的主机等;
6. 选择主机:选择打分最高的主机,进行binding操作,结果存储到Etcd中;
7. kubelet根据调度结果执行Pod创建操作: 绑定成功后,会启动container, docker run, scheduler会调用API Server的API在etcd中创建一个bound pod对象,描述在一个工作节点上绑定运行的所有pod信息。运行在每个工作节点上的kubelet也会定期与etcd同步bound pod信息,一旦发现应该在该工作节点上运行的bound pod对象没有更新,则调用Docker API创建并启动pod内的容器。
2. 环境
2.1. Kubernetes:1.5.2
3. 安装与配置:参考文章:http://www.cnblogs.com/breezey/p/6545307.html
3.1. 在所有节点上都安装docker
yum install docker
3.2. 配置docker信任我们前面做的仓库,修改/usr/lib/systemd/system/docker.service
[Unit] Description=Docker Application Container Engine Documentation=http://docs.docker.com After=network.target Wants=docker-storage-setup.service Requires=rhel-push-plugin.socket registries.service Requires=docker-cleanup.timer [Service] Type=notify NotifyAccess=all EnvironmentFile=-/run/containers/registries.conf EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network Environment=GOTRACEBACK=crash Environment=DOCKER_HTTP_HOST_COMPAT=1 Environment=PATH=/usr/libexec/docker:/usr/bin:/usr/sbin ExecStart=/usr/bin/dockerd-current --insecure-registry hctjosadm01.hccos.cn:5000 --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --authorization-plugin=rhel-push-plugin --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current $OPTIONS $DOCKER_STORAGE_OPTIONS $DOCKER_NETWORK_OPTIONS $ADD_REGISTRY $BLOCK_REGISTRY $INSECURE_REGISTRY $REGISTRIES ExecReload=/bin/kill -s HUP $MAINPID LimitNOFILE=1048576 LimitNPROC=1048576 LimitCORE=infinity TimeoutStartSec=0 Restart=on-abnormal MountFlags=slave KillMode=process [Install] WantedBy=multi-user.target
3.3. 设置服务随机启动
systemctl daemon-reload && systemctl enable docker && systemctl start docker
3.4. 在master节点上安装kuber master
yum install -y kubernetes-master kubernetes-client
3.5. 在master节点上修改配置文件 /etc/kubernetes/config
### # kubernetes system config # # The following values are used to configure various aspects of all # kubernetes services, including # # kube-apiserver.service # kube-controller-manager.service # kube-scheduler.service # kubelet.service # kube-proxy.service # logging to stderr means we get it in the systemd journal KUBE_LOGTOSTDERR="--logtostderr=true" # journal message level, 0 is debug KUBE_LOG_LEVEL="--v=0" # Should this cluster be allowed to run privileged docker containers KUBE_ALLOW_PRIV="--allow-privileged=false" # How the controller-manager, scheduler, and proxy find the apiserver KUBE_MASTER="--master=http://172.16.0.90:8080"
3.6. 记得创建一个key文件,要不在创建pod的时候会报错
openssl genrsa -out /etc/kubernetes/serviceaccount.key 2048
3.7. 在master节点上修改配置文件 /etc/kubernetes/apiserver
### # kubernetes system config # # The following values are used to configure the kube-apiserver # # The address on the local server to listen to. #KUBE_API_ADDRESS="--insecure-bind-address=127.0.0.1" KUBE_API_ADDRESS="--address=0.0.0.0" # The port on the local server to listen on. # KUBE_API_PORT="--port=8080" KUBE_API_PORT="--port=8080 --secure-port=443" KUBE_MASTER="--master=http://172.16.0.90:8080" # Port minions listen on # KUBELET_PORT="--kubelet-port=10250" KUBELET_PORT="--kubelet-port=10250" # Comma separated list of nodes in the etcd cluster #KUBE_ETCD_SERVERS="--etcd-servers=http://127.0.0.1:2379" KUBE_ETCD_SERVERS="--etcd-servers=http://172.16.0.83:2379,http://172.16.0.84:2379,http://172.16.0.85:2379" # Address range to use for services KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16" # default admission control policies KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota" # Add your own! #KUBE_API_ARGS="--service_account_key_file=/etc/kubernetes/serviceaccount.key"
3.8. 修改/etc/kubernetes/controller-manager
### # The following values are used to configure the kubernetes controller-manager # defaults from config and apiserver should be adequate # Add your own! KUBE_CONTROLLER_MANAGER_ARGS="--service_account_private_key_file=/etc/kubernetes/serviceaccount.key"
3.9. 启动master上的服务
systemctl start kube-apiserver kube-controller-manager kube-scheduler
systemctl enable kube-apiserver kube-controller-manager kube-scheduler
3.10. 在所有node节点上安装服务
yum install -y kubernetes-node
3.11. 修改node上的配置文件 /etc/kubernetes/config
### # kubernetes system config # # The following values are used to configure various aspects of all # kubernetes services, including # # kube-apiserver.service # kube-controller-manager.service # kube-scheduler.service # kubelet.service # kube-proxy.service # logging to stderr means we get it in the systemd journal KUBE_LOGTOSTDERR="--logtostderr=true" # journal message level, 0 is debug KUBE_LOG_LEVEL="--v=0" # Should this cluster be allowed to run privileged docker containers KUBE_ALLOW_PRIV="--allow-privileged=false" # How the controller-manager, scheduler, and proxy find the apiserver KUBE_MASTER="--master=http://172.16.0.90:8080"
3.12. 修改node节点上的配置文件/etc/kubernetes/kubelet
### # kubernetes kubelet (minion) config # The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces) #KUBELET_ADDRESS="--address=127.0.0.1" KUBELET_ADDRESS="--address=0.0.0.0" # The port for the info server to serve on # KUBELET_PORT="--port=10250" # You may leave this blank to use the actual hostname KUBELET_HOSTNAME="--hostname-override=hctjosk8snode01" # location of the api-server KUBELET_API_SERVER="--api-servers=http://172.16.0.90:8080" # pod infrastructure container KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest" # Add your own! KUBELET_ARGS=""
3.13. 启动node节点上的服务
systemctl start kubelet kube-proxy
systemctl enable kubelet kube-proxy
3.14. 在主节点上查看集群状态
~]# kubectl get nodes
NAME STATUS AGE
hctjosk8snode01 Ready 1h
hctjosk8snode02 Ready 18s
hctjosk8snode03 Ready 15s
hctjosk8snode04 Ready 11s
3.15. 在所有node节点上吧flannel安装上
yum install flannel
3.16. 在etcd服务器上(10.30.2.83/84/85任意一台即可),增加一条记录
etcdctl set /hccos.cn/network/config '{"network": "172.17.0.0/16"}'
3.17. 修改flannel配置文件 /etc/sysconfig/flanneld
# Flanneld configuration options # etcd url location. Point this to the server where etcd runs FLANNEL_ETCD_ENDPOINTS="http://172.16.0.83:2379,http://172.16.0.84:2379,http://172.16.0.85:2379" # etcd config key. This is the configuration key that flannel queries # For address range assignment FLANNEL_ETCD_PREFIX="/hccos.cn/network" # Any additional options that you want to pass #FLANNEL_OPTIONS=""
3.18. 启动服务
systemctl start flanneld
systemctl enable flanneld
3.19. 由于docker依赖于flanneld,需要重启docker服务
systemctl restart docker
4. YAML文件示例
#test-pod
apiVersion: v1 #指定api版本,此值必须在kubectl apiversion中
kind: Pod #指定创建资源的角色/类型
metadata: #资源的元数据/属性
name: test-pod #资源的名字,在同一个namespace中必须唯一
labels: #设定资源的标签
k8s-app: apache
version: v1
kubernetes.io/cluster-service: "true"
annotations: #自定义注解列表
- name: String #自定义注解名字
spec: #specification of the resource content 指定该资源的内容
restartPolicy: Always #表明该容器一直运行,默认k8s的策略,在此容器退出后,会立即创建一个相同的容器
nodeSelector: #节点选择,先给主机打标签kubectl label nodes kube-node1 zone=node1
zone: node1
containers:
- name: test-pod #容器的名字
image: 10.192.21.18:5000/test/chat:latest #容器使用的镜像地址
imagePullPolicy: Never #三个选择Always、Never、IfNotPresent,每次启动时检查和更新(从registery)images的策略,
# Always,每次都检查
# Never,每次都不检查(不管本地是否有)
# IfNotPresent,如果本地有就不检查,如果没有就拉取
command: ['sh'] #启动容器的运行命令,将覆盖容器中的Entrypoint,对应Dockefile中的ENTRYPOINT
args: ["$(str)"] #启动容器的命令参数,对应Dockerfile中CMD参数
env: #指定容器中的环境变量
- name: str #变量的名字
value: "/etc/run.sh" #变量的值
resources: #资源管理
requests: #容器运行时,最低资源需求,也就是说最少需要多少资源容器才能正常运行
cpu: 0.1 #CPU资源(核数),两种方式,浮点数或者是整数+m,0.1=100m,最少值为0.001核(1m)
memory: 32Mi #内存使用量
limits: #资源限制
cpu: 0.5
memory: 1000Mi
ports:
- containerPort: 80 #容器开发对外的端口
name: httpd #名称
protocol: TCP
livenessProbe: #pod内容器健康检查的设置
httpGet: #通过httpget检查健康,返回200-399之间,则认为容器正常
path: / #URI地址
port: 80
#host: 127.0.0.1 #主机地址
scheme: HTTP
initialDelaySeconds: 180 #表明第一次检测在容器启动后多长时间后开始
timeoutSeconds: 5 #检测的超时时间
periodSeconds: 15 #检查间隔时间
#也可以用这种方法
#exec: 执行命令的方法进行监测,如果其退出码不为0,则认为容器正常
# command:
# - cat
# - /tmp/health
#也可以用这种方法
#tcpSocket: //通过tcpSocket检查健康
# port: number
lifecycle: #生命周期管理
postStart: #容器运行之前运行的任务
exec:
command:
- 'sh'
- 'yum upgrade -y'
preStop:#容器关闭之前运行的任务
exec:
command: ['service httpd stop']
volumeMounts: #挂载持久存储卷
- name: volume #挂载设备的名字,与volumes[*].name 需要对应
mountPath: /data #挂载到容器的某个路径下
readOnly: True
volumes: #定义一组挂载设备
- name: volume #定义一个挂载设备的名字
#meptyDir: {}
hostPath:
path: /opt #挂载设备类型为hostPath,路径为宿主机下的/opt,这里设备类型支持很多种
#nfs