kubernetes简介

1、k8s简介

Kubernetes(k8s)是Google开源的容器集群管理系统,是一个完备集群管理能力的分布式系统支撑平台。

先简单概览下官方master/slave集群架构图:

kubernetes的prm包下载教程_kubernetes的prm包下载教程


假设图中是我们的三台“主机”,其中右侧两台是放我们应用的服务器,也就是k8s中的Node,在k8s中通过左侧的Master来管理我们的Node。

先说Masterkubectl是k8s中的命令行操作工具,类似docker命令;Authentication是k8s的认证,Authorization是k8s的授权;API Server提供了集群管理的API接口和负责集群内功能模块的数据交互和通信;Kubernetes以RESTFul形式开放接口;Scheduler是集群中的调度器,负责Pod在集群中节点的调度分配;controller manager是k8s的管理控制中心;etcd是一个高可用的键值存储系统,在k8s中用于存储集群中所有的资源对象的信息并被监控。

再说Node:Node是Kubernetes集群中相对Master而言的工作主机,可以是一台物理机、虚拟机或者云服务器;kubelet负责本Node上的Pod创建、修改、监控和删除等全生命周期管理,同时定时上报本Node的状态信息;Proxy实现Service的代理及软件模式的负载均衡;cAdvisor是一个用于监控容器运行状态的开源软件,k8s中默认被集成到kubelet组件中。

2、基本概念和术语

Kubernetes中Service、Pod、Master、Node、RC、label等概念都可以看作一种资源对象,通过Kubernetes提供的Kubectl工具或API调用进行操作,并保存在etcd中。

Node:
是Kubernetes集群中相对Master而言的工作主机。Node包含的信息:Node的地址(“主机”ip地址)或者Node ID、Node运行状态、Node系统容量描述、Node可用的系统资源、还包括实例信息等,在Node上运行的服务进程包括Kubelet、Kube-proxy和docker daemon。

Pod:
是Kubernetes的最基本操作单元,Pod在Node上被创建、启动或销毁,通过Yaml或者Json格式的配置文件来定义。一个Pod包含一个或多个容器,Pod中的多个容器应用通常是紧耦合的。创建Pod的原因是由于Docker容器之间的通信受到Docker网络机制的限制,虽然容器之间可以通过link的方式访问,但是通过Pod的概念可以将一个Pod当做一个“虚拟机”,Pod中的容器就是这台“虚拟机”中的所有应用,也就是说可以将Node当做我们的“物理机”,然后在我们的“物理机”中创建一个“虚拟机”,“虚拟机”内当然可以通过localhost实现通信,也方便管理,一个Pod中的应用容器可以看到其他应用程序的进程ID。

以下是简单的Master、Node、Pod和container的关系图:

kubernetes的prm包下载教程_Pod_02


图中Master管理多个Node,Node中包含多个Pod,Pod中包含多个容器。

Lable:
是Kubernetes系统中的一个核心概念。Lable以key/value键值对的形式附加到各种资源对象上,如Pod、Service、RC、Node等,并且每个对象可以具有多个Lable,在为“对象”定义好Lable后,其他“对象”就可以使用Lable Selector来定义其作用的对象了。Lable Selector分为基于等式或者基于集合的形式,类似sql中的“=”、“!=”、“in”、“not in”语句,或者js中的name标签。

Replication Controller(RC):
是Kubernates系统中的核心概念,可以通过yaml或json格式的配置文件定义Pod副本的数量,并且可以手动修改,在Master内,Controller Manager进程通过RC的定义和Node的上的某个程序(如Kubelet或Docker)来完成Pod的创建、监控、启停等操作,如果运行了过多的Pod,RC会停掉一些Pod,如果运行了Pod数过少,则RC会启动相应数量的Pod,如果需要删除所有Pod,可以将Pod的数量修改为0,也就是RC可以控制Kubernetes的扩容缩容。

Job:
job类似RC,只是RC是持续管理pod,而Job是一次性创建后就完成结束,删除job会清理掉该job创建的pod。

Daemon Set:
如果需要所有节点(或部分)节点都运行某一个pod(比如日志、监控)可以创建Daemon Set,当这些节点添加到集群中时pod也会被添加,如果某个节点从集群中删除,则这些节点的pod会被垃圾回收,删除Daemon Set将清理它创建的pod。

Replica Set(RS):
是下一代“RC”Replica Set和Replication Controller的区别是,它支持基于集合的选择器要求,而RC仅支持基于等式的选择器。虽然Replica Set可以单独存在管理pod,但是它主要的功能是配合Deployments来进行管理pod。

Deployment:
对pod和Replica Set进行声明和更新。典型的实例:创建部署得到Replica Set和Pods;检查部署的状态,以查看其是否成功;更新该部署以重新创建Pod(例如,使用新的镜像);如果当前部署不稳定,回滚到早期的部署版本;暂停和恢复部署。

Service:
是一个虚拟概念,逻辑上代理后端pod,可以看作一组提供相同服务的Pod对外访问接口,拥有一个唯一的指定的名字,一个虚拟IP或端口号,能够提供某种远程服务能力,可以通过Lable Selector来定义Service作用于哪些Pod。如果外部需要访问,可以对外提供Service的type定义:NodePort端口映射和LoadBalancer自定义负载,这样即使运行在不同Node上面相同Lable的Pod,也可以定义Service的Lable Selector和port让外部通过port来访问任何一个该Lable的Pod。如果一个Service需要对外暴露多个端口,可给每个port定义不同的name来区分。

kube-proxy:
每个工作节点都会运行一个kube-proxy服务进程,通过kube-proxy实现流量从service到pod的转发,kube-proxy还可以实现简单的负载均衡功能。kube-proxy有多种代理模式,kube-proxy在工作节点上为每一个服务创建一个临时端口,service的ip:port过来的流量转发到这个临时端口上,kube-proxy会用内部的负载均衡机制(默认是轮寻)选择一个后端pod,然后建立iptables,把流量导入到某个pod里。Kubernetes 支持两种服务发现模式,分别是环境变量和dns。使用环境变量的时候会在pod创建的时候,服务的ip和port信息以环境变量的形式注入到pod里,比如服务ip地址是192.168.1.1,port是8080,则会把下面一系列环境变量注入到pod里,通过这些环境变量获取服务的ip和port。Kubernetes集群内会内置一个dns服务器,service创建成功后,会在dns服务器里导入一些记录,想要访问某个服务,通过dns服务器解析出对应的ip和port,从而实现服务访问。

结合Lable概念说明:

kubernetes的prm包下载教程_Pod_03


图中每个Pod有两个标签,如果在Service的配置中定义Lable Selector属性为name:tomcat,并且ip地址为192.168.1.216,端口号为8080,那么我们可以通过192.168.1.216:8080同时访问Pod1和Pod3;如果在Service的配置中定义Lable Selector属性为version:1,ip地址为192.168.1.216,端口号为80,那么我们可以通过192.168.1.216:80同时访问Pod1和Pod2。

Pod的概念让我们方便在同一个Pod中通过localhost加端口号来访问不同的容器,而Service让我们方便在同一个Node或外部通过ip地址加端口号来访问不同的“服务器”。

Volume:
是Pod中能够被多个容器访问的共享目录,类似Docker的Volume,只是Pod的Volume生命周期与Pod相同,于容器不相干,并且一个Pod可以有多个Volume。Kubernetes提供两种Volume类型:EmptyDir初始内容为空,同一个Pod中的容器可以读写EmptyDir中的相同文件,如果Pod从Node上移除EmptyDir中的数据也会永远删除;hostPath是在Pod上挂载宿主机上的文件或目录;还可以使用其他存储设备、网络上的永久磁盘或文件系统等作为Volume。

Namespace:
简单的说namespace的定义是为了限制集群范围内的资源访问,即使是同一个用户也不能跨namespace访问资源。

3、服务组件

  • Master:

Etcd:是一个高可用的键值存储系统,在k8s中用于持续化集群中所有的资源对象并被监控。
API server:提供了资源对象的唯一操作入口,其他组件都必须通过它提供的API来操作资源数据。
Controller Manager:集群内部的管理控制中心,其主要目的是实现Kubernetes集群的故障检测和恢复的自动化工作。
Scheduler:集群中的调度器,将待调度的Pod按照特定的调度算法和调度策略绑定到集群中某个合适的Node上。

  • Node:

kubelet:每个Node上都会启动一个Kubelet服务进程,负责本Node节点上管理监控本Node和本Node上的Pod和容器。
Proxy:实现了Service的代理及软件模式的负载均衡器。

  • 创建基本对象流程

kubernetes中基本的对象为Pod、Replication Controller和Service。

Create Pod:

kubernetes的prm包下载教程_API_04


简单说明下Create Pod的过程:

首先用户通过命令行工具(kubecfg也是命令行工具,在新版Kubernetes中,所有的操作命令都整合至kubectl,包括kubecfg、kubectl.sh、kubecfg.sh等)向apiserver提交创建Pod的请求,apiserver将请求的Pod信息对象存储到etcd中;然后scheduler周期性的通过apiserver访问etcd中需要创建的Pod的信息,并且通过调度算法和策略给需要创建的Pod分配Node;最后kubelet周期性的访问etcd需要创建的Pod的信息,通过docker创建并且启动一个容器。Create ReplicationController:

kubernetes的prm包下载教程_docker_05

Create Service:

kubernetes的prm包下载教程_API_06

安装部署

1、资源准备
master(centos 3.10.0-327.el7.x86_64): 192.168.1.187
node(centos 3.10.0-327.el7.x86_64): 192.168.1.107
node(centos 3.10.0-327.el7.x86_64): 192.168.1.105
docker(1.12.3)
kubernetes(1.4.1)

2、修改对应主机名、关闭防火墙和selinux

hostnamectl set-hostname master-187
hostnamectl set-hostname node-107
hostnamectl set-hostname node-105

3、所有主机添加docker的yum源

tee /etc/yum.repos.d/docker.repo <<-'EOF'
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/7/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF

4、所有主机安装启动docker

yum install -y docker-engine
systemctl enable docker
systemctl start docker

5、所有主机添加kubernetes1.4的(国内)yum源

cat <<EOF> /etc/yum.repos.d/k8s.repo
[kubelet]
name=kubelet
baseurl=http://files.rm-rf.ca/rpms/kubelet/
enabled=1
gpgcheck=0
EOF

6、master主机资源准备

  • 下载镜像(版本号不能变,否则创建集群的时候可能导致镜像检查失败不能初始化):
docker pull mritd/kube-proxy-amd64:v1.4.1
docker pull mritd/kube-discovery-amd64:1.0
docker pull mritd/kubedns-amd64:1.7
docker pull mritd/kube-scheduler-amd64:v1.4.1
docker pull mritd/kube-controller-manager-amd64:v1.4.1
docker pull mritd/kube-apiserver-amd64:v1.4.1
docker pull mritd/etcd-amd64:2.2.5
docker pull mritd/kube-dnsmasq-amd64:1.3
docker pull mritd/exechealthz-amd64:1.1
docker pull mritd/pause-amd64:3.0
  • 打标镜像:
docker tag mritd/kube-proxy-amd64:v1.4.1  gcr.io/google_containers/kube-proxy-amd64:v1.4.1
docker tag mritd/kube-discovery-amd64:1.0 gcr.io/google_containers/kube-discovery-amd64:1.0
docker tag mritd/kubedns-amd64:1.7  gcr.io/google_containers/kubedns-amd64:1.7
docker tag mritd/kube-scheduler-amd64:v1.4.1  gcr.io/google_containers/kube-scheduler-amd64:v1.4.1
docker tag mritd/kube-controller-manager-amd64:v1.4.1  gcr.io/google_containers/kube-controller-manager-amd64:v1.4.1
docker tag mritd/kube-apiserver-amd64:v1.4.1  gcr.io/google_containers/kube-apiserver-amd64:v1.4.1
docker tag mritd/etcd-amd64:2.2.5  gcr.io/google_containers/etcd-amd64:2.2.5
docker tag mritd/kube-dnsmasq-amd64:1.3  gcr.io/google_containers/kube-dnsmasq-amd64:1.3
docker tag mritd/exechealthz-amd64:1.1  gcr.io/google_containers/exechealthz-amd64:1.1
docker tag mritd/pause-amd64:3.0  gcr.io/google_containers/pause-amd64:3.0
  • 删除多余镜像:
docker rmi mritd/kube-proxy-amd64:v1.4.1
docker rmi mritd/kube-discovery-amd64:1.0
docker rmi mritd/kubedns-amd64:1.7
docker rmi mritd/kube-scheduler-amd64:v1.4.1
docker rmi mritd/kube-controller-manager-amd64:v1.4.1
docker rmi mritd/kube-apiserver-amd64:v1.4.1
docker rmi mritd/etcd-amd64:2.2.5
docker rmi mritd/kube-dnsmasq-amd64:1.3
docker rmi mritd/exechealthz-amd64:1.1
docker rmi mritd/pause-amd64:3.0
  • 或者编辑镜像更新脚本:
images=(kube-proxy-amd64:v1.4.1 kube-discovery-amd64:1.0 kubedns-amd64:1.7 kube-scheduler-amd64:v1.4.1 kube-controller-manager-amd64:v1.4.1 kube-apiserver-amd64:v1.4.1 etcd-amd64:2.2.5 kube-dnsmasq-amd64:1.3 exechealthz-amd64:1.1 pause-amd64:3.0)
for imageName in ${images[@]} ; do
  docker pull mritd/$imageName
  docker tag mritd/$imageName gcr.io/google_containers/$imageName
  docker rmi mritd/$imageName
done
  • 安装kubernetes相关组件:
yum install -y kubelet kubeadm kubectl kubernetes-cni ebtables
systemctl enable kubelet
systemctl start kubelet
  • 编辑/etc/hosts文件:
    master创建的pod是运行在node上的,如果不加入节点的ip会按照节点名找节点,会提示no such host。

7、node主机资源准备

  • 镜像准备(只需要kube-proxy-amd64和kube-proxy-amd64):
docker pull mritd/kube-proxy-amd64:v1.4.1
docker pull mritd/pause-amd64:3.0
docker tag mritd/kube-proxy-amd64:v1.4.1  gcr.io/google_containers/kube-proxy-amd64:v1.4.1
docker tag mritd/pause-amd64:3.0  gcr.io/google_containers/pause-amd64:3.0
docker rmi mritd/kube-proxy-amd64:v1.4.1
docker rmi mritd/pause-amd64:3.0
  • 安装kubernetes相关组件:
yum install -y kubelet kubeadm
systemctl enable kubelet
systemctl start kubelet

8、创建集群

  • 初始化集群:
kubeadm init --api-advertise-addresses=192.168.1.187

集群创建成功后会显示如下图:

kubernetes的prm包下载教程_Pod_07

如果显示到:

<master/apiclient> created API client, waiting for the control plane to become ready

很久也没有往下进行很可能是镜像的版本不匹配,需要重新下载不匹配的镜像。最后的显示的是加入集群的命令,需要记一下,暂时没有找到该token存储的位置。

kubeadm join --token=f1bfac.5df27d2c6aebf2cc 192.168.1.187
  • 重置集群

如果集群出现问题可以重置集群,重新init,以下是官网简化的命令:

kubeadm reset

kubernetes的prm包下载教程_kubernetes的prm包下载教程_08


但是重置的时候会停掉所有运行的docker镜像,需要注意。

  • 节点加入
kubeadm join --token=f1bfac.5df27d2c6aebf2cc 192.168.1.187

节点加入成功后会显示如下图:

kubernetes的prm包下载教程_kubernetes的prm包下载教程_09


如果提示:

<node/bootstrap> endpoint check failed [failed to connect to https://192.168.1.187:6443[Get https://192.168.1.187:6443/version: x509: certificate has expired or is not yet valid]]<node/bootstrap> trying to connect to endpoint https://192.168.1.187:6443

类似的信息,是你的docker证书过期,使用date命令检查下系统时间是否和当前时间一致,如果不一致需要更新系统时间。

yum -y install ntp
ntpdate cn.pool.ntp.org

如果显示找不到主机的路由是因为没有关闭防火墙。

集群加入成功可以在master上检查下:

kubectl get node

kubernetes的prm包下载教程_API_10

  • master主机创建weave网络

如果master主机没有配置weave网络,dns是不会启动的,查看系统默认启动的pod:

kubectl get pod --namespace=kube-system

kubernetes的prm包下载教程_kubernetes的prm包下载教程_11


查看该pod的详细信息(pod后面跟的是你自己的pod名称不要写错):

kubectl describe pod kube-dns-2247936740-0xx49 --namespace=kube-system

kubernetes的prm包下载教程_kubernetes的prm包下载教程_12

提示无法设置网络,无法分配ip,这时候需要创建weave网络:

kubectl create -f https://git.io/weave-kube

weave创建成功显示如下:

kubernetes的prm包下载教程_Pod_13

kubernetes的prm包下载教程_docker_14


该创建过程可能会很慢因为创建weave网络的时候需要在每个主机上下载

weaveworks/weave-npc:1.8.1和weaveworks/weave-kube:1.8.1两个镜像,可以提前下载好,重新查看下dns的pod信息:

kubernetes的prm包下载教程_API_15

9、创建pod

  • 创建一个简单的pod示例

先编辑一个busybox.yaml作为pod的yaml文件:

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  hostname: busybox-1
  subdomain: default
  containers:
  - image: busybox
    command:
      - sleep
      - "3600"
    name: busybox

创建pod:

kubectl create -f busybox.yaml

如果node节点没有busybox的镜像会先下载,所以过程需要等一下,创建后显示:

kubectl get pod

kubernetes的prm包下载教程_Pod_16


查看pod的详情:

kubectl describe pod busybox

kubernetes的prm包下载教程_Pod_17


Node属性后面显示的就是该pod被创建的node节点名称和ip,可以107节点上查看是否下载了相关镜像:

kubernetes的prm包下载教程_docker_18

  • 创建多个跨主机通信的pod示例(借用kubernetes权威指南示例,略微修改 )

首先创建一个mysql的RC:

apiVersion: v1
kind: ReplicationController
metadata:
  name: mysql
spec:
  replicas: 1
  selector: 
    app: mysql
  template:
    metadata:
      labels: 
        app: mysql
    spec: 
      containers:
        - name: mysql
          image: mysql
          ports: 
          - containerPort: 3306
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: '123456'

RC中定义需要运行一个pod,再创建一个mysql的service用于外部通信:

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql

service中定义访问接口是3306, 再创建一个应用的RC:

apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb
spec:
  replicas: 5
  selector: 
    app: myweb
  template:
    metadata:
      labels: 
        app: myweb
    spec: 
      containers:
        - name: myweb
          image: kubeguide/tomcat-app:v1
          ports: 
          - containerPort: 8080

RC中定义需要运行五个pod,使用一个自定义的tomcat镜像,再创建一个应用的service用于外部通信:

apiVersion: v1
kind: Service
metadata:
  name: myweb
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30001
  selector:
    app: myweb

service中定义对外暴露的接口是30001访问接口是8080,在这个应用镜像中定义了一些mysql的环境变量,用于访问mysql,如果节点主机没有相应镜像可能会有点慢,运行结果如下:

kubernetes的prm包下载教程_API_19


查看应用中的环境变量:

kubernetes的prm包下载教程_API_20


可以使用describe或logs来查看某个pod的详情和日志,如果运行成功在浏览器通过master主机ip加30001访问tomcat,加demo可以访问我们应用的示例:

kubernetes的prm包下载教程_docker_21