什么是 Kubernetes

概述

简写成 K8s。K8s 是底层资源与容器间的一个抽象层,算作是一个分布式时代的 Linux

K8s 是 Google 开源的容器集群管理系统。在 Docker 技术的基础上,为容器化的应用提供部署运行资源调度服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。

K8s 是一个完备的分布式系统支撑平台,具有完备的集群管理能力,多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和发现机制、內建负载均衡器、强大的故障发现自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制。提供涵盖了开发、部署、测试、运维监控各环节的管理工具。

Kubernetes 特点:

  1. 可移植:支持公有云,私有云,混合云;
  2. 可扩展:模块化,热插拨,可组合;
  3. 自愈:自动替换,自动重启,自动复制,自动扩展。

 

现状

Docker 兴起时, 大家都不看好 K8s,纷纷选择了 Mesos。 从 1.0 开始,K8s 很快就远远地把所有竞争对手甩在了后面。K8s 开源后,已经迅速成为了容器管理领域的事实标准。

目前 K8s 最新版本已经到了 1.9.6, 越来越多的厂商加入到 K8s 阵营。

其 Github 地址为: https://github.com/kubernetes/kubernetes

 

Kubernetes 总览

总体架构

 

enter image description here

从图上可看出,这里边有两类节点,第一类是 Master 节点,即主控节点;第二类是 Node 节点,即工作节点。

Master 节点:负责控制和维护整个集群的状态,比如创建资源、删除资源。

Node 节点:负责运行任务,比如启动容器。

K8s 控制逻辑只依赖于当前状态、容错处理、自动恢复和鲁棒性。

(1)控制逻辑只依赖于当前状态

对于分布式系统来说,出现局部错误的频率非常地高,如果控制逻辑只依赖当前状态,那么就非常容易将一个暂时出现故障的系统恢复到正常状态,这无论对于开发者还是运维人员都能带来极大好处。

(2)组件的容错处理

在一个分布式系统中出现局部和临时错误是大概率事件。错误可能来自于物理系统故障,外部系统故障也可能来自于系统自身的代码错误,因此要设计对任何可能错误的容错处理。

(3)自动恢复和鲁棒性

K8s 设计成各模块间耦合性都比较松散,比如 Apiserver 异常后,也不会影响到集群业务的正常运转。K8s 设计成无论哪个组件异常,总能比较好地自动恢复。

K8s 通过资源抽象,简化运维和开发。

K8s 将集群中所有的任务抽象成资源,比如一个 Deployment 资源、一个 Pod 资源。用户面向的是一个一个资源,客户端只能通过操作这些资源来控制整个集群。这样的设计,有几个明显地好处,第一就是模型非常简单和一致,对于开发者来说,只需要理解了这种资源的模式,就很容易维护 K8s 里边的任何代码。第二就是通过资源这个抽象层,将模块与模块之间做了很好地隔离,从而很容易做到各模块之间的对接和独立升级维护。

基本概念

K8s 涉及到的基本概念非常多,这里只是简单过一下,不一个一个介绍,详细信息可以直接查文档或 Google。

  • Pod:K8s 的基本运行单元;
  • ReplicaSet:Pod 的集合;
  • Deployment:提供更新支持;
  • StatefulSets:提供有状态支持;
  • Volume:数据卷;
  • Labels:标签,资源间的关联一般通过这个来实现。

相关组件

Master 相关组件

Master 即主控节点, 相当于整个集群的大脑。

Master 提供集群的管理控制中心,通常情况下,Master 会独立部署,不在上面跑用户容器,以保证整个集群的稳定性和安全。当然可以跑多个 Master 来达到高可用。

Master 主要组件包括:Kube-apiserver、Kube-controller-manager、Etcd。

  • Kube-apiserver

Kube-apiserver 用于暴露 Kubernetes API。任何的资源请求/调用操作都是通过 Kube-apiserver 提供的接口进行。

  • Kube-controller-manager

Kube-controller-manager:运行管理控制器,它们是集群中处理常规任务的后台线程。逻辑上,每个控制器是一个单独的进程,但为了降低复杂性,它们都被编译成单个二进制文件,并在单个进程中运行。

  • Etcd

Etcd 是 Kubernetes 提供默认的存储系统,保存所有集群数据。所以一般推荐使用时要为 Etcd 数据提供备份计划。

Node 相关组件

Node 即工作节点, 相当于整个集群的身体。

Node 节点负责从 Master 处接收任务并执行,适当地时候调整自己的状态或删除过期的负载。

Node 主要组件包括:Kubelet、Kube-proxy、Docker/Rkt。

  • Kubelet

kubelet 是工作节点主要的程序,它会监视已分配给节点的 pod,具体功能包括:

  • 创建 Pod 所需的数据卷;

  • 创建 Pod 所需的网络;

  • 下载 Pod 的Secrets;

  • 启动 Pod 中运行的容器;

  • 定期执行容器健康检查;

  • 上报节点状态。

  • Kube-proxy

Kube-proxy 通过在主机上维护网络规则并执行连接转发来实现 Kubernetes 服务抽象。

  • Docker/Rkt

Docker/Rkt 用于运行容器。

Kubernetes 安装部署

部署目标

为了让大家更简单地部署和理解 K8s 集群,接下来我将采用纯手工的方式部署 K8s 集群,并以最小化的方式部署。整个集群将由两个节点组成,包含1个 Master 节点, 1个 Node 节点, Etcd 装在 Master 节点上。

需要提醒大家的是,如果是部署到生产环境,考虑到安全性和可靠性,建议将 Etcd 单独部署,并启用 Https。

部署整体结构如下:

enter image description here

相关版本

  • Kubernetes v1.9.6
  • Etcd v3.2.9
  • Docker v17.10.0-ce

资源说明

IP AddressRoleCPU Memory
192.168.139.190master8核 16G
192.168.139.189node8核 16G

详细部署过程

安装 Docker

安装 Docker 比较简单,对于正常的 Unbuntu 或 Centos,Docker 提供安装脚本可以自动安装。具体命令如下:

curl -fsSL "https://get.docker.com/" | sh

安装 Etcd

为了方便,我们可以直接从 Github 上下载二进制安装。

  • 下载 Etcd
wget https://github.com/coreos/etcd/releases/download/v3.3.2/etcd-v3.3.2-linux-amd64.tar.gz
  • 启动Etcd
wlb@docker-sxf:~/pr-common/kubernetes/etcd-v3.3.2-linux-amd64$]$ ./etcd 
2018-03-24 14:31:11.957802 I | etcdmain: etcd Version: 3.3.2
2018-03-24 14:31:11.957950 I | etcdmain: Git SHA: c9d46ab37
...
2018-03-24 14:31:12.963064 I | embed: ready to serve client requests
2018-03-24 14:31:12.964414 N | embed: serving insecure client requests on 127.0.0.1:2379, this is strongly discouraged!

安装 Master 服务

Master 服务主要包含 kube-apiserver、kube-controller-manager、kube-scheduler,分别是 API 服务、资源控制服务和资源调度服务。

同样,Kubernetes 在 Github 上也提供二进制下载, 非常方便。

  • 下载 Master 服务

#  wget https://dl.k8s.io/v1.9.6/kubernetes-server-linux-amd64.tar.gz

  • 编辑配置

root@hongkong-web1:~/k8sbin# cat /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="--address=0.0.0.0"
    #KUBE_API_ADDRESS="--insecure-bind-address=127.0.0.1"

    # The port on the local server to listen on.
    KUBE_API_PORT="--port=8080"

    # Port minions listen on
    KUBELET_PORT="--kubelet-port=10250"

 

  • 启动 Master 服务

(1)启动 Apiserver。

#  ./kube-apiserver   --etcd-servers  http://127.0.0.1:2379 

I0601 16:13:03.686789   24778 server.go:121] Version: v1.9.6
......
I0601 16:13:09.937901   24778 cache.go:39] Caches are synced for autoregister controller

(2)启动 Scheduler。

# ./kube-scheduler --master http://127.0.0.1:8080

root@hongkong-web1:~/k8s/server/kubernetes/server/bin# ./kube-scheduler --master http://127.0.0.1:8080
W0601 16:17:19.580855   24791 server.go:162] WARNING: all flags than --config are deprecated. Please begin using a config file ASAP.
I0601 16:17:19.586263   24791 server.go:554] Version: v1.9.6
I0601 16:17:19.586732   24791 server.go:573] starting healthz server on 0.0.0.0:10251
I0601 16:17:20.387780   24791 controller_utils.go:1019] Waiting for caches to sync for scheduler controller
I0601 16:17:20.488133   24791 controller_utils.go:1026] Caches are synced for scheduler controller
I0601 16:17:20.488451   24791 leaderelection.go:174] attempting to acquire leader lease...
I0601 16:17:20.493398   24791 leaderelection.go:184] successfully acquired lease kube-system/kube-scheduler

(3)启动 Controller-manager。

# ./kube-controller-manager --master http://127.0.0.1:8080

root@hongkong-web1:~/k8s/server/kubernetes/server/bin# ./kube-controller-manager --master http://127.0.0.1:8080
I0601 16:23:23.209535   24833 controllermanager.go:108] Version: v1.9.6
......
I0601 16:23:26.947905   24833 controller_utils.go:1019] Waiting for caches to sync for garbage collector controller
I0601 16:23:27.048371   24833 controller_utils.go:1026] Caches are synced for garbage collector controller

(4)查看主控状态。

root@hongkong-web1:~/k8s/server/kubernetes/server/bin# ./kubectl cluster-info
Kubernetes master is running at http://localhost:8080

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.


root@hongkong-web1:~/k8s/server/kubernetes/server/bin# ./kubectl get cs
NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok                  
controller-manager   Healthy   ok                 

至此,整个 K8s 的 Master 服务已经部署完了,通过 kubectl get cs 命令,我们可以看到所有的主控服务都已经处于 Healthy 状态。


安装 Node 服务

K8s 是主从式架构,主控上运行的服务比较多,而从结点相对就简单很多。

这里主要介绍部署 Pod 相关的 Kubelet 服务和 Service 相关的 Kube-proxy 服务。值得注意的是,由于 K8s 设计成插件化的网络和存储架构,所以从节点上可以按需部署各类网络插件和存储插件,篇幅限制,这里不做介绍,有兴趣可以参考官方文档。

安装 Master 服务

#   wget https://dl.k8s.io/v1.9.6/kubernetes-node-linux-amd64.tar.gz

 

(1)启动 Kubelet 服务

新版本的 K8s 必须要创建一个 Kubeconfig 配置文件,让 Kubelet 能接入 Master。

Kubeconfig 文件示例如下:

wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ cat kubeconfig 
current-context: test-context
apiVersion: v1
clusters:
- cluster:
    api-version: v1
    server: http://127.0.0.1:8080
  name: test-cluster
contexts:
- context:
    cluster: test-cluster
    namespace: default
  name: test-context
kind: Config
preferences:
  colors: true
wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ sudo ./kubelet --fail-swap-on=false --kubeconfig ./kubeconfig  --containerd 
I0324 15:11:20.554107     516 feature_gate.go:226] feature gates: &{{} map[]}
I0324 15:11:20.554241     516 controller.go:114] kubelet config controller: starting controller
I0324 15:11:20.554258     516 controller.go:118] kubelet config controller: validating combination of defaults and flags
I0324 15:11:20.559898     516 server.go:182] Version: v1.9.6
...
I0324 15:11:24.063305     516 server.go:129] Starting to listen on 0.0.0.0:10250
I0324 15:11:24.064261     516 server.go:299] Adding debug handlers to kubelet server.
I0324 15:11:24.068791     516 fs_resource_analyzer.go:66] Starting FS ResourceAnalyzer

(2)启动 Kube-proxy 服务。

wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ sudo ./kube-proxy --master http://127.0.0.1:8080
W0324 15:22:02.807447    1254 server.go:185] WARNING: all flags other than --config, --write-config-to, and --cleanup are deprecated. Please begin using a config file ASAP.
I0324 15:22:02.821052    1254 server_others.go:138] Using iptables Proxier.
...
I0324 15:22:02.948357    1254 controller_utils.go:1026] Caches are synced for endpoints config controller

(3)通过 kubectl get nodes 命令查看节点状态。

wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/server/bin$]$ ./kubectl get nodes
NAME         STATUS    ROLES     AGE       VERSION
ubuntu       Ready     <none>    1h        v1.9.6

至此,从节点已经部署完了。是不是觉得整个部署过程非常简单呢?

Kubernetes 应用开发

K8s 集群创建完后,就可以使用它来创建我们需要的应用了。K8s 的很大一个优点是对开发者很友好,提供了大量的 API 及客户端工具,比如创建应用,最简单的方法,直接通过 Kubectl run 就可以做到。

快速创建应用

下面以一个 Nginx 应用示例来介绍。

(1)通过 kubctl run 创建应用。

通过指定容器镜像、副本数量及端口,就可以启动一个应用。

wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ ./kubectl run nginx --image=nginx --replicas=2 --port=80 --expose=true
service "nginx" created
deployment "nginx" created
wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ ./kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
nginx-7587c6fdb6-9sd9d   0/1       Pending   0          5s
nginx-7587c6fdb6-kvfsq   0/1       Pending   0          5s
wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ ./kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP   51m
nginx        ClusterIP   10.0.0.40    <none>        80/TCP    11s

(2)导出服务让外部可访问.

通过 kubectl run 创建的应用,默认情况下服务是一个虚拟 IP,从集群外部访问是访问不到的,这时需要用到 NodePort 类型的服务,将节点端口映射到容器内部。

wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ ./kubectl expose deployment nginx --type=NodePort --name=nginx-nodeport
service "nginx-nodeport" exposed
wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ ./kubectl get deployment
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx     2         2         2            0           5m
wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ ./kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
nginx-7587c6fdb6-9sd9d   0/1       Pending   0          5m
nginx-7587c6fdb6-kvfsq   0/1       Pending   0          5m
wlb@docker-sxf:~/pr-common/kubernetes/kubernetes/node/bin$]$ ./kubectl get svc
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
kubernetes       ClusterIP   10.0.0.1     <none>        443/TCP        57m
nginx            ClusterIP   10.0.0.40    <none>        80/TCP         5m
nginx-nodeport   NodePort    10.0.0.67    <none>        80:30147/TCP   8s

(3)通过 http://192.168.139.190:30147 访问应用。

效果如下:

nginx

复杂应用开发

除了创建这种简单的单体应用,K8s 还有更强大的功能,就是它的应用编排。通过 K8s 提供的资源编排脚本, 我们可以很轻松地开发和部署分布式应用。下面以一个大数据应用 Storm 为例(参考 K8s 官方给出的一个例子), 给大家介绍如何开发一个复杂的分布式应用。

(1) 创建 ZooKeeper Pod。

在前面的章节已经跟大家介绍了 Pod 的概念, 这里可以将 Pod 理解成一个容器, 通过下面的脚本,可以启动一个 Zookeeper Pod。

注:实际生产环境,要对 Zookeeper 做好备份。

$ kubectl create -f examples/storm/zookeeper.json

{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "zookeeper",
    "labels": {
      "name": "zookeeper"
    }
  },
  "spec": {
    "containers": [
      {
        "name": "zookeeper",
        "image": "mattf/zookeeper",
        "ports": [
          {
            "containerPort": 2181
          }
        ],
        "resources": {
          "limits": {
            "cpu": "100m"
          }
        }
      }
    ]
  }
}

(2)创建 Zookeeper Service。

K8s 的 Service 可以理解成服务的概念, 一个 Service 对应多个 Pod;K8s 通过标签来关联 Service 和 Pod。

$ kubectl create -f examples/storm/zookeeper-service.json

{
  "kind": "Service",
  "apiVersion": "v1",
  "metadata": {
    "name": "zookeeper",
    "labels": {
      "name": "zookeeper"
    }
  },
  "spec": {
    "ports": [
      {
        "port": 2181
      }
    ],
    "selector": {
      "name": "zookeeper"
    }
  }
}

(3)创建 Storm-nimbus Pod。

$ kubectl create -f storm-nimbus.json
{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "nimbus",
    "labels": {
      "name": "nimbus"
    }
  },
  "spec": {
    "containers": [
      {
        "name": "nimbus",
        "image": "mattf/storm-nimbus",
        "ports": [
          {
            "containerPort": 6627
          }
        ],
        "resources": {
          "limits": {
            "cpu": "100m"
          }
        }
      }
    ]
  }
}

(4)创建 Storm-nimbus 服务。

$ kubectl create -f storm-nimbus-service.json
{
  "kind": "Service",
  "apiVersion": "v1",
  "metadata": {
    "name": "nimbus",
    "labels": {
      "name": "nimbus"
    }
  },
  "spec": {
    "ports": [
      {
        "port": 6627
      }
    ],
    "selector": {
      "name": "nimbus"
    }
  }
}

(5)创建 Storm-worker Deployment。

Deployment 是一个控制器, 通过下面的配置,实际会启动两个 storm-worker 副本。

$ kubectl create -f storm-worker-controller.yaml

apiVersion: apps/v1  
use extensions/v1beta1
kind: Deployment
metadata:
  name: storm-worker-controller
  labels:
     name: storm-worker
spec:
  replicas: 2
  selector:
     matchLabels:
        name: storm-worker
        uses: nimbus
  template:
    metadata:
      labels:
        name: storm-worker
        uses: nimbus
    spec:
      containers:
      - name: storm-worke
        image: mattf/storm-worker
        resources:
          limits:
            cpu: 200m
            memory: 500Mi
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - hostPort: 6700
          containerPort: 6700
        - hostPort: 6701
          containerPort: 6701
        - hostPort: 6702
          containerPort: 6702
        - hostPort: 6703
          containerPort: 6703

(5)通过上面的步骤创建完 Storm 后, 就可以直接访问了。

$  echo stat | nc 10.10.1.141 2181; echo
Zookeeper version: 3.4.6--1, built on 10/23/2014 14:18 GMT
Clients:
 /192.168.48.0:44187[0](queued=0,recved=1,sent=0)
 /192.168.45.0:39568[1](queued=0,recved=14072,sent=14072)
 /192.168.86.1:57591[1](queued=0,recved=34,sent=34)
 /192.168.8.0:50375[1](queued=0,recved=34,sent=34)

Latency min/avg/max: 0/2/2570
Received: 23199
Sent: 23198
Connections: 4
Outstanding: 0
Zxid: 0xa39
Mode: standalone
Node count: 13

上面的例子简单介绍了基于 K8s 的应用编排开发,有兴趣的读者可以进一步交流。

另外 K8s 在 Github 上给出了大量例子,也非常值得进一步学习。

如果期望对 K8s 应用编排有更深的理解, 可以查看 Chart 主页, Chart 上提供了大量可供用户一键安装的 K8s 应用。

chart

Kubernetes 小经验

最后一些我们在 K8s 引入和使用的过程中遇到的问题和积累的一些经验,在这里分享给大家。

1.不要盲目选型,先搞清楚业务需求,再确定是否需要 K8s。

引入任何的分布系统都意味着复杂度的大幅提升,虽然 K8s 设计上非常简洁,但是对于普通开发人员来讲,其复杂度仍然不低,出了问题排障也不容易。所以建议,能单机解决的不要考虑分布式,不要为了技术而选择技术。

2.将 Etcd 单独部署。

因为 Etcd 是整个集群的存储中心,是需要小心保护的,一旦出问题,很大可能会影响整个集群的可用性。

3.尽量保证大部分的应用无状态。

尽管 K8s 提供了承载有状态应用的方案,但是有状态意味着需要额外地关心应用状态,这会给后续运维带来很大的挑战。

4.尽量保证大部分的 Node 节点可被快速替换。

意思是不要在 Node 上存太关键的数据,当 Node 故障时, 我们可以在不需要做太多额外工作的情况下将其快速将其剔除。如果需要存储状态,应当对集群分区,让不同角色的节点运行不同的应用。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐