初识Kubernetes
什么是 Kubernetes概述Kubernetes,简写成 K8s。K8s 是底层资源与容器间的一个抽象层,算作是一个分布式时代的 Linux。K8s 是 Google 开源的容器集群管理系统。在 Docker 技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。K8s 是一个完备的分布式系统支撑平台,具有...
什么是 Kubernetes
概述
简写成 K8s。K8s 是底层资源与容器间的一个抽象层,算作是一个分布式时代的 Linux。
K8s 是 Google 开源的容器集群管理系统。在 Docker 技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。
K8s 是一个完备的分布式系统支撑平台,具有完备的集群管理能力,多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和发现机制、內建负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制。提供涵盖了开发、部署、测试、运维监控各环节的管理工具。
Kubernetes 特点:
- 可移植:支持公有云,私有云,混合云;
- 可扩展:模块化,热插拨,可组合;
- 自愈:自动替换,自动重启,自动复制,自动扩展。
现状
Docker 兴起时, 大家都不看好 K8s,纷纷选择了 Mesos。 从 1.0 开始,K8s 很快就远远地把所有竞争对手甩在了后面。K8s 开源后,已经迅速成为了容器管理领域的事实标准。
目前 K8s 最新版本已经到了 1.9.6, 越来越多的厂商加入到 K8s 阵营。
其 Github 地址为: https://github.com/kubernetes/kubernetes。
Kubernetes 总览
总体架构
从图上可看出,这里边有两类节点,第一类是 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。
部署整体结构如下:
相关版本
- Kubernetes v1.9.6
- Etcd v3.2.9
- Docker v17.10.0-ce
资源说明
IP Address | Role | CPU Memory |
---|---|---|
192.168.139.190 | master | 8核 16G |
192.168.139.189 | node | 8核 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 访问应用。
效果如下:
复杂应用开发
除了创建这种简单的单体应用,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 应用。
Kubernetes 小经验
最后一些我们在 K8s 引入和使用的过程中遇到的问题和积累的一些经验,在这里分享给大家。
1.不要盲目选型,先搞清楚业务需求,再确定是否需要 K8s。
引入任何的分布系统都意味着复杂度的大幅提升,虽然 K8s 设计上非常简洁,但是对于普通开发人员来讲,其复杂度仍然不低,出了问题排障也不容易。所以建议,能单机解决的不要考虑分布式,不要为了技术而选择技术。
2.将 Etcd 单独部署。
因为 Etcd 是整个集群的存储中心,是需要小心保护的,一旦出问题,很大可能会影响整个集群的可用性。
3.尽量保证大部分的应用无状态。
尽管 K8s 提供了承载有状态应用的方案,但是有状态意味着需要额外地关心应用状态,这会给后续运维带来很大的挑战。
4.尽量保证大部分的 Node 节点可被快速替换。
意思是不要在 Node 上存太关键的数据,当 Node 故障时, 我们可以在不需要做太多额外工作的情况下将其快速将其剔除。如果需要存储状态,应当对集群分区,让不同角色的节点运行不同的应用。
更多推荐
所有评论(0)