1. Kubernetes介绍
要了解Kubernetes,首先我们需要了解Container与Orchestration。
Docker
Docker的出现是为了解决:部署依赖、以及兼容性、以及繁琐的启动配置问题
Docker使用的是底层的OS(也就是docker中的share kernel)。在container中,虽然定义了AMI中的操作系统,但是实际上,Container中不会运行一个OS,而是使用底层的OS Kernel。如下图所示:
与之不同的是Virtual Machine,云计算虚拟机中,底层同样是Hardware Infrastructure 以及 OS。然后是Docker这层对应的是Hypervisor,之上就是VM。每个Virtual Machine中也是有Libs与Deps,以及Application运行,这些都与Container一样。唯一不同的地方在于,VM中有一套独立的OS,而Container均是使用的底层shared OS。所以VM中会大量使用底层系统资源,而Docker不会使用大量底层资源,且启动速度相对来说会更快。
Docker中的Image可以封装一个执行环境,我们可以通过docker运行一个Image,以保证运行环境的一致性。
安装docker
在各个节点上均安装docker:
sudo yum install docker
启动 docker 守护进程:
sudo /etc/init.d/docker start
测试docker run:
sudo docker run docker/whalesay cowsay boo
Container Orchestration
现在我们知道了Docker 与 Container,在一个Docker Host 上,可以运行多个Docker Container。
但是在生产环境中,场景会更为复杂,常见的需求如:
- 一个Container依赖于另外的Container,如Web Container 依赖于 MySQL Container
- 根据流量,Container扩容与缩容
为了满足这些需求,首先我们至少需要多个Docker Host,以提供更多的Container 资源用于运行。之后我们还需要一个用于跨Docker Host 管理Container的系统,便是Container Orchestration:
当前主要有三种Orchestration技术,分别为:
- Docker Swarm :由Docker提出。部署简单,便于使用,但是缺少一些高级功能,对复杂应用的使用场景有限
- Kubernetes:当前最流行。部署稍微复杂,可以提供很多用户自定义部署,并支持部署复杂的架构
- Mesos:由Apache提出。部署复杂,但是支持一些高级功能
所以Kubernetes是一种Orchestration技术,可用于部署并管理集群中成千上万的Containers,实现用户业务架构。
Kubernetes Set Up
这里我们选择Kubeadm工具进行部署,基于以下顺序:
- 一个Master节点以及(一个或多个)Worker节点
- 在所有节点上均安装并启动docker守护进程
- 在所有节点上均安装kubeadm
- 初始化Master节点
- 设置Master与Worker节点间的POD Network
- 将Worker节点加入Master节点
以上是自建时所需要做的步骤,不过当前有各种第三方工具可用于部署。这里我们使用的是 kops,实例我们使用的是 AWS EC2。kops的官方文档如下:
https://github.com/kubernetes/kops/blob/master/docs/getting_started/aws.md
kops将集群的状态保存在s3中,所以我们需要创建一个 kops 用的 s3 桶,这个桶也会用于保存集群配置。
在使用 kops 启动集群后,我们可以使用kubectl 确认一下节点状态:
> kubectl get nodes
NAME STATUS ROLES AGE VERSION
Ip-xx.xx.xx.xx Ready node 3h2m v1.15.5
Ip-xx.xx.xx.xx Ready node 3h2m v1.15.5
Ip-xx.xx.xx.xx Ready master 3h3m v1.15.5
集群组件
在 Kubernetes 中,构成K8s集群的很多组件都是使用k8s自身进行部署的,所有k8s组件都在kube-system 命名空间下,我们接下来介绍以下几个比较重要的组件。
Kubernetes Proxy
Kubernetes Proxy 负责转发网络流量到 Kubernetes 集群中的负载均衡服务。为了完成此目的,proxy必须在每个节点上都运行。K8s有一个API对象名为DaemonSet,在很多集群中都是通过它完成的此任务。不过这取决于集群的配置,并不是所有集群都用的 DaemonSet。但是集群中所有集群都会运行kube-proxy container。
Kubernetes DNS
K8s 也会运行一个DNS server,它为集群内部的dns 命名与解析提供服务。这个DNS server也会以一个replicated service 运行在集群中。根据集群的大小,我们可能会看到一个或多个DNS servers。一个运行的dns server如:
> kubectl get deployments --namespace=kube-system kube-dns
NAME READY UP-TO-DATE AVAILABLE AGE
kube-dns 2/2 2 2 5h18m
也会有 k8s 服务用于为 DNS server 做负载均衡,如:
> kubectl get service --namespace=kube-system kube-dns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 100.64.0.10 <none> 53/UDP,53/TCP 5h18m
这个负载均衡使得集群的 DNS 服务有一个ip地址(100.64.0.10)。如果我们登录到一个container中,则可以看到这个地址已被写入到了 /etc/resolv.conf 文件。
2. Kubernetes 组件
一个Kubernetes集群由控制节点(master)和工作节点(node)构成,每个节点上都会安装不同的组件。
- Master:集群的控制层面,负责集群的决策。
- ApiServer:资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制
- Scheduler:负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上。例如根据负载,计算到将Pod调度到node 1 上,但并不负责分配的工作,只计算,分配由ControllerManager 完成
- ControllerManager:负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等
- Etcd:负责存储集群中各种资源对象的信息,默认用的etcd,也可以配置为其他数据库。例如Pod在哪个节点。
- Node:集群的数据层面,负责为容器提供运行环境
- Kubelet:负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器
- KubeProxy:负责提供集群内部的服务发现和负载均衡;例如Pod部署了一个nginx,外部需要访问到它时,需通过KubeProxy
- Docker:负责节点上容器的各种操作
如下图所示:
各组件之间调用关系
下面以部署一个nginx服务,来说明kubernetes系统各个组件之间的调用关系:
- 首先要明确,一旦kubernetes环境启动后,master和node都会将自身的信息存储到etcd数据库中
- 一个nginx服务器的安装请求会首先发送到master的apiServer
- apiServer组件会调用scheduler组件来决定到底应该把哪个服务安装到哪个node节点上。此时,它会从etcd中读取各个node节点的信息,然后按照一定的算法进行选择,并将结果告知apiServer
- apiServer调用controller-manager去调度Node节点安装nginx服务
- kubelet接受到指令后,会通知docker,然后由docker来启动一个nginx的pod。Pod是kubernetes的最小操作单元,容器必须跑在pod中
- 一个nginx服务就运行了,如果需要访问nginx,就需要通过kube-proxy来对pod产生访问的代理。
这样,外网用户即可访问集群中的nginx服务了。
Kubernetes 各个概念
- Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控
- Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器运行
- Pod:kubernetes的最小控制单元,容器都是运行在pod中的,一个pod中可以有1个或多个容器
- Controller:控制器,通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等等
- Service:pod对外服务的统一入口,下面可以维护同一类的多个pod
- Label:标签,用于对pod进行分类,同一pod会拥有相同的标签
- NameSpace:命令空间,用来隔离pod的运行环境
如下图所示:
为了让外部分访问到tomcat服务,需要通过一个Service来提供。可以看到Service只映射到了其中3个tomcat 的Pod,这就是通过 Label 对不同的Pod进行的分类。这个是kubernetes定义的标签-选择器机制,通过标签进行定义,通过选择器来进行选择。
默认情况下,所有pod都是可以相互访问的。若是需要隔离访问,则就需要通过NameSpace来实现了。它会对pod进行逻辑区分,仅有同一个NameSpace的pod能够互相访问,实现隔离。
3. Kubernetes 集群
集群分类
Kubernetes集群大体上分为两类:一主多从和多主多从。
- 一主多从:1台Master节点和多台Node节点,搭建简单,但有单机故障风险,适合用于测试环境
- 多主多从:多台Master节点和多台Node节点,搭建麻烦,安全性高,适合用于生产环境
安装方式
主流方式有kubeadm、minikube、二进制包
- minikube:快速搭建单节点kubernetes集群
- kubeadm:快速搭建kubernetes集群
- 二进制包:从官网下载每个组件的二进制包,依次安装,非常麻烦
在kubernetes中service有2种代理模型,一种基于iptables,一种基于ipvs。相较来说,ipvs的性能明显要高一些,但是如果要使用它,需要手动载入ipvs模块。
4. 访问 aws eks
1. 启动 eks 集群后,先在客户端安装必要软件:
kubectl:
https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/install-kubectl.html
eksctl:
https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/eksctl.html
2. 配置kubeconfig
aws eks --region <region-code> update-kubeconfig --name <cluster_name>
检查是否可以访问:
> kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-10-0-1-217.cn-north-1.compute.internal Ready <none> 110m v1.18.9-eks-d1db3c
需要注意的是:当您创建 Amazon EKS 集群时,将在控制层面内集群的 RBAC 配置中自动为 IAM 实体用户或角色(例如,创建集群的联合身份用户)授予 system:masters 权限。此 IAM 实体不会出现在 ConfigMap 或任何其他可见配置中,因此请确保保持跟踪哪个 IAM 实体最初创建了集群。要授予其他 AWS 用户或角色与您的集群进行交互的能力,您必须编辑 Kubernetes 内的 aws-auth ConfigMap
也就是说,只有创建集群的用户有权限访问集群。若是需要为其他Role或User添加访问集群权限,则需要参考:
https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/add-user-role.html
一个参考的配置:
$ cat aws-auth-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws-cn:iam::xxxxx:role/xxxxx
username: ec2admin
groups:
- system:masters
- rolearn: arn:aws-cn:iam::xxxxxx:role/eks_node
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
5. 测试集群
尝试部署一个nginx程序:
# 部署nginx
kubectl create deployment nginx --image=nginx:1.14-alpine
# 暴露端口
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看服务状态,svc就是service
$ kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-55f8fd7cfc-7qzdd 1/1 Running 0 76s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 4h7m
service/nginx NodePort 172.20.172.246 <none> 80:30210/TCP 26s
=> 此配置说明的是,需要通过访问节点的30210 的端口,此端口会映射到节点的80端口。
# curl node 节点的 30210 端口
$ curl 10.0.1.217:30210
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
…