一、概念简介
Kubernetes是Google开源的容器集群管理系统。它构建Ddocker技术之上,为容器化的应用提供资源调度、部署运行、服务发现、扩容缩容等整一套功能,本质上可看作是基于容器技术的mini-PaaS平台。本文旨在梳理Kubernetes的架构、概念及基本工作流,并且通过运行一个简单的示例应用来介绍如何使用Kubernetes。
优点:
—轻量级、简单
—公有云、私有云、混合云部署
—模块化、可插拔化、可挂接、可组合
—自动恢复、自动重启、自动复制
总体概览
如下图(网上摘的,经典图)所示,基本上可以从如下三个维度来认识Kubernetes。
操作对象
Kubernetes以RESTFul形式开放接口,用户可操作的REST对象有三个:
- pod:是Kubernetes最基本的部署调度单元,可以包含container,逻辑上表示某种应用的一个实例。比如一个web站点应用由前端、后端及数据库构建而成,这三个组件将运行在各自的容器中,那么我们可以创建包含三个container的pod。
- service:是pod的路由代理抽象,用于解决pod之间的服务发现问题。因为pod的运行状态可动态变化(比如切换机器了、缩容过程中被终止了等),所以访问端不能以写死IP的方式去访问该pod提供的服务。service的引入旨在保证pod的动态变化对访问端透明,访问端只需要知道service的地址,由service来提供代理。
- replicationController:是pod的复制抽象,用于解决pod的扩容缩容问题。通常,分布式应用为了性能或高可用性的考虑,需要复制多份资源,并且根据负载情况动态伸缩。通过replicationController,我们可以指定一个应用需要几份复制,Kubernetes将为每份复制创建一个pod,并且保证实际运行pod数量总是与该复制数量相等(例如,当前某个pod宕机时,自动创建新的pod来替换)。可以看到,service和replicationController只是建立在pod之上的抽象,最终是要作用于pod的,那么它们如何跟pod联系起来呢?这就要引入label的概念:label其实很好理解,就是为pod加上可用于搜索或关联的一组key/value标签,而service和replicationController正是通过label来与pod关联的。如下图所示,有三个pod都有label为”app=backend”,创建service和replicationController时可以指定同样的label:”app=backend”,再通过label selector机制,就将它们与这三个pod关联起来了。例如,当有其他frontend pod访问该service时,自动会转发到其中的一个backend pod。
功能组件
master运行三个组件:
- apiserver:作为kubernetes系统的入口,封装了核心对象的增删改查操作,以RESTFul接口方式提供给外部客户和内部组件调用。它维护的REST对象将持久化到etcd(一个分布式强一致性的key/value存储)。
- scheduler:负责集群的资源调度,为新建的pod分配机器。这部分工作分出来变成一个组件,意味着可以很方便地替换成其他的调度器。
- controller-manager:负责执行各种控制器,目前有两类:
- endpoint-controller:定期关联service和pod(关联信息由endpoint对象维护),保证service到pod的映射总是最新的。
- replication-controller:定期关联replicationController和pod,保证replicationController定义的复制数量与实际运行pod的数量总是一致的。
slave(称作minion)运行两个组件:
- kubelet:负责管控docker容器,如启动/停止、监控运行状态等。它会定期从etcd获取分配到本机的pod,并根据pod信息启动或停止相应的容器。同时,它也会接收apiserver的HTTP请求,汇报pod的运行状态。
- proxy:负责为pod提供代理。它会定期从etcd获取所有的service,并根据service信息创建代理。当某个客户pod要访问其他pod时,访问请求会经过本机proxy做转发。
功能特性
将在之后慢慢融入
二、最初搭建
需要至少一个master和一个minion,为了方便以后操作,可以先定义hosts(这里只用了两台,如果做两台以上需要网络支持,参考之前Docker网络部分)
10.20.161.77 centos-master
10.20.161.88 centos-minion
1、使用yum安装【master、minion】
vim /etc/yum.repos.d/virt7-testing.repo
1 2 3 4 |
|
如果之前安装了docker,防止版本冲突,需要卸载之前安装的版本,安装kubernetes的时候会自动安装docker。
1 |
|
2、关闭防火墙【master、minion】
systemctl disable iptables-services firewalld
systemctl stop iptables-services firewalld
3、修改公共配置文件【master、minion】
vim /etc/kubernetes/config
KUBE_MASTER=”–master=http://centos-master:8080″
KUBE_ETCD_SERVERS=”–etcd_servers=http://centos-master:4001″ #下面安装
4、安装etcd【master】
yum install http://cbs.centos.org/kojifiles/packages/etcd/0.4.6/7.el7.centos/x86_64/etcd-0.4.6-7.el7.centos.x86_64.rpm
5、修改apiserver配置文件【master】
vim /etc/kubernetes/apiserver
KUBE_API_ADDRESS=”–address=0.0.0.0″
KUBE_API_PORT=”–port=8080″
#KUBE_ETCD_SERVERS=”–etcd_servers=http://127.0.0.1:2379″ 注释掉
6、启动master相关服务(全部为active running状态则为正常,否则tail -f /var/log/messages |grep kube查看错误日志)
vim /etc/init.d/kubernetes-master
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
7、修改kubelet配置文件【minion】
vim /etc/kubernetes/kubelet
KUBELET_ADDRESS=”–address=0.0.0.0″
KUBELET_PORT=”–port=10250″
KUBELET_HOSTNAME=”–hostname_override=centos-minion”
KUBELET_API_SERVER=”–api_servers=http://centos-master:8080“
8、启动minion相关服务【minion】
vim kubernetes-minion
参考上面脚本修改即可。
9、minion导入根镜像pause【minion】PS:所有容器的根镜像,必备。因可能被墙,所以需要手动导入。
下载地址:http://pan.baidu.com/s/1o72tqSq
1 2 |
|
10、查看状态是否正常【master】
kubectl get nodes
查看到节点注册成功,则表明系统安装正常
三、常用命令(持续更新)
https://cloud.google.com/container-engine/docs/kubectl/ #官网参数详解
kubectl –help
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
1、常用操作类
kubectl create -f XXX.yaml 根据yaml文件创建指定的资源 –validate检测配置文件是否正确
kubectl delete pod POD_NAME 删除指定pod
kubectl scale rc RC名 –replicas=5 动态调整pod数量
kubectl rolling-update RC名 –update-period=3s –image=XXXX 每隔3秒钟进行更新images
kubectl patch pod valid-pod -p ‘{“spec”:{“containers”:[{"name":"kubernetes-serve-hostname","image":"new image"}]}}’ 修改vaild-pod的image名称
kubectl run nginx-test01 –image=10.20.161.77:5000/nginx 运行一个rc
2、常用排错类
kubectl get po,rc,svc 查看pods、rc、service列表
kubectl describe pod POD_NAME 查看某个pod的具体信息
kubectl get pod nginx -o yaml 以yaml的格式输出pod更详细的信息
kubectl get nodes 查看工作节点列表
kubectl get events 查看事件信息
kubectl logs POD_NAME 查看pod的输出日志
kubectl label nodes centos-minion01 zone=minion01 设置node的label标签
四、资源配置解析(期待完善)
kubernetes里面几乎一切都是资源,那么创建各种资源就依赖于配置文件,跟好多软件类似,k8s默认装好也就是空壳,什么都没有,一切都需要自己定义各种配置文件,然后基于配置文件来创建资源。下面就开始来解析各类配置文件。Google官方说明地址:https://htmlpreview.github.io/?https://github.com/kubernetes/kubernetes/HEAD/docs/api-reference/v1/definitions.html
Pods:目的是为了更好的进行资源共享以及容期间的通信
- 创建、调度以及管理的最小单元(docker里是容器,在k8s的世界里是pods)
- 共存的一组容器的集合(也就是说pods是一个或者多个容器组成的单位)
- 容器共享PID、网络、IPC以及UTS命名空间(同一个pod里的容器可以看到彼此的进程,可以使用同样的ip及端口,可以使用System V IPC或者posix通信,可以使用相同的主机名)
- 容器共享存储卷(同一个pods里的容器可以共享存储卷)
- 短暂存在(和容器一样属于短暂存在,共四个状态:Pending(指令已被系统接受,但容器并未创建)、Running(成功运行)、Successed(pod里的容器已被成功停止)、Failed(pod里的容器出现停止错误))
- 下面来创建一个pod例子
vim nginx-pod.yaml
1 2 3 4 5 6 7 8 9 10 |
|
kubectl create -f nginx-pod.yaml
列一些常用参数:
command: ["/bin/echo"]
args: ["hello","world"]
Volumes:目的是为了解决数据的持久化问题
- 数据持久化(容器的数据是短暂存在的,当容器奔溃时,数据丢失,Volumes就是为了解决这个问题)
- pod中容器共享数据(同一pod里的容器可以共享数据)
- 生命周期(和定义pod的生命周期一样,当一个pod被停止退出,那么volumes也停止退出)
- 支持多种类型的数据卷
- emptyDir:初始为空,是在Pod分配到Node时创建,当Pod移除时,emptyDir里的数据也会永久删除。但当容器奔溃时,数据不会删除。
用途:
临时空间,例如用于某些应用程序运行时所需的临时目录,且无需永久保留
长时间任务的中间过程CheckPoint临时保存目录
一个容器需要从另一个容器中获取数据的目录(多容器共享目录)
- hostpath:在Pod上挂载宿主机上的文件或目录
用途:
容器应用程序生成的日志文件需要永久保留,可以使用宿主机的告诉文件系统进行存储
需要访问宿主机上Docker引擎内部数据的容器应用,可以通过定义hostpath为宿主机/var/lib/docker目录使用容器内部应用可以直接访问Docker的文件系统
需要注意:
在不同Node上具有相同配置的pod可能会因为宿主机上的目录和文件不同而导致对Volumes上目录和文件访问结果不一致
- 云存储:gcePersistentDisk、awkElasticBlockStore
- 网络存储:nfs、iscsi、glusterfs
- secrets:用来保存敏感数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Lables:目的是为了更方便的选取对象
- 用以标示对象(如Pod)的key/value对(就是比如定义pod的时候定义一个 app:nginx,那么选择的时候就可以通过标签选择器选择所有app=nginx的pod)
- 组织并选择对象子集
1 2 3 4 5 6 7 8 9 10 11 12 |
|
选择的话可以使用参数 -l,例如:kubectl get pods -l app=nginx
Replication Controllers:目的是保证pods始终保持预定义的状态运行,rc应该算是k8s里最棒的设计了。
- 确保在任一时刻运行指定数目的Pod
- 容器重新调度(监控多台主机上的多个pod,当A主机上出现问题,那么会自动把A主机上的pod调度到B主机上。)
- 规模调整(如果要规模调整,那么只需要修改需要运行的pod数量,rc便会根据现有的数量进行增减操作)
- 在线升级(通过一个接着一个的升级替换的方式,可以实现在线升级。需要至少一处lables不同以标记不同版本)
- 多发布版本跟踪
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
创建好之后,就可以使用kubectl get rc nginx-controller来查看刚刚创建的rc。
PS:可以做个小验证:查看pods关于刚刚创建好的pod有两个,是以nginx-controller开头的。手动delete一个。看会发生什么?
Services:目的是解决了pod对外访问的问题
- 抽象一系列Pod并定义其访问规则
- 固定ip地址和DNS域名
- 通过环境变量和DNS发现服务
- 负载均衡
- 外部服务
- ClusterIP:使用集群内的私有ip —— 这是默认值。
- NodePort:除了使用cluster ip外,也将service的port映射到每个node的一个指定内部port上,映射的每个node的内部port都一样。PS:网上有说法是在工作节点暴露端口,其实准确说法应该是node上映射一个随机端口来指向service里定义的端口,然后通过iptables的规则来实现转发。具体解析见最后附
- LoadBalancer:使用一个ClusterIP & NodePort,但是会向cloud provider申请映射到service本身的负载均衡。 (注意:NodePort支持TCP/UDP,LoadBalancer只支持TCP)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
PS:如果习惯使用–validate来测试配置文件的话,有可能测试service的时候会一直报:error validating data: field nodePort: is required。网上查了说可能是bug,忽略错误,直接创建即可。
–service-node-port-range=: A port range to reserve for services with NodePort visibility. Example: ’30000-32767′. 用来指定服务映射的端口范围
五、常见问题(持续更新)
1、启动kubernetes时,查看日志出现如下提示,是因为没有相应的目录,以及授权。
Nov 13 19:19:29 xutao kube-apiserver[13630]: E1113 19:19:29.981529 13630 server.go:454] Unable to generate self signed cert: open /var/run/kubernetes/apiserver.crt: permission denied
Nov 13 19:19:29 xutao kube-apiserver[13630]: E1113 19:19:29.981624 13630 server.go:464] Unable to listen for secure (open /var/run/kubernetes/apiserver.crt: no such file or directory); will try again.
解决办法:
vim /usr/lib/systemd/system/kube-apiserver.service
1 2 3 4 |
|
systemctl daemon-reload
重启kube-apiserver
systemctl restart kube-apiserver.service
systemctl status kube-apiserver.service
或者(关闭https):
vim /etc/kubernetes/apiserver
可以在KUBE_API_ARGS加上–secure-port=0
systemctl restart kube-apiserver.service
2、使用yaml文件创建资源时出现如下提示,是由于默认开启了鉴权,关闭接口。
[root@xutao kubernetes]# kubectl create -f nginx-pod.yaml
Error from server: error when creating “nginx-pod.yaml”: Pod “nginx” is forbidden: no API token found for service account default/default, retry after the token is automatically created and added to the service account
解决办法:
vim /etc/kubernetes/apiserver
1 |
|
将ServiceAccount,去掉
systemctl restart kube-apiserver 重启apiserver服务
3、创建pod时出现如下提示,是由于缺少的镜像pause被墙了。
解决办法:
需要pause的镜像,可以现在这个已经被墙,使用附件的tar包,手动导入到docker里。(具体见上方部署部分)
也可以指定内网仓库
vim /etc/kubernetes/kubelet
KUBELET_ARGS=”–pod-infra-container-image=docker3:5000/pause:latest”
4、etcd版本问题,原因为新版的端口和旧版本的端口不一致
解决办法(两种):
- 更改为旧版本0.4.6
- 更改apiserver的配置文件,使用2379端口
5、docker无法启动,原因有可能磁盘不够,或者没有解析到。
Nov 19 20:29:36 centos7 systemd: Starting Docker Storage Setup…
Nov 19 20:29:36 centos7 docker-storage-setup: Rounding up size to full physical extent 32.00 MiB
Nov 19 20:29:36 centos7 docker-storage-setup: Volume group “centos_centos7″ has insufficient free space (0 extents): 8 required.
Nov 19 20:29:36 centos7 systemd: docker-storage-setup.service: main process exited, code=exited, status=5/NOTINSSTALLED
Nov 19 20:29:36 centos7 systemd: Failed to start Docker Storage Setup.
Nov 19 20:29:36 centos7 systemd: Unit docker-storage-setup.service entered failed state.
Nov 19 20:29:36 centos7 systemd: Starting Docker Application Container Engine…
Nov 19 20:29:36 centos7 docker: time=”2015-11-19T20:29:36.538243264+08:00″ level=info msg=”Listening for HTTP on unix (/var/run/docker.sock)”
Nov 19 20:29:36 centos7 docker: time=”2015-11-19T20:29:36.540394247+08:00″ level=error msg=”WARNING: No –storage-opt dm.thinpooldev specified, using loopback; this configuration is strongly discouraged for production use”
解决办法:
增加vg容量,重启机器试试
不行就删除 /usr/lib/systemd/system/docker.service 里的DOCKER_STORAGE_OPTIONS
systemctl daemon-reload
systemctl restart docker.service
6、还是无法启动docker,原因可能为docker没有识别到正常的thinpooldev,需要手动指定
Error starting daemon: error initializing graphdriver: EOF
/usr/bin/docker daemon –selinux-enabled –storage-driver devicemapper –storage-opt dm.fs=xfs –storage-opt dm.thinpooldev=/dev/mapper/centos_centos7-docker–pool-tpool
解决办法:
https://gist.github.com/joshix/ec1673f2791bf5cb352f#file-thin-pool-md
dmsetup status
找到tpool结尾的那行,比如centos_centos7-docker–pool-tpool
修改文件
vim /etc/sysconfig/docker-storage
DOCKER_STORAGE_OPTIONS=–storage-driver devicemapper –storage-opt dm.fs=xfs –storage-opt dm.thinpooldev=/dev/mapper/centos_centos7-docker–pool-tpool
重启
systemctl daemon-reload
systemctl restart docker.service
7、node为不可用状态,查看日志发现
Nov 19 16:19:57 centos-master kube-controller-manager: W1119 16:19:57.618729 11352 nodecontroller.go:256] Missing timestamp for Node centos-minion01. Assuming now as a timestamp.
解决办法:
尝试时间同步
8、pull镜像失败,原因是没有添加信任地址
Failed to pull image “10.20.161.77:5000/mysql”: unable to ping registry endpoint https://10.20.161.77:5000/v0/
解决办法:
手动添加信任关系
vim /etc/sysconfig/docker
INSECURE_REGISTRY=’–insecure-registry 10.20.161.77:5000′
重启服务
systemctl restart docker
9、node上iptables的问题
[root@centos-minion01 shell]# iptables -nL –line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all – 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 ACCEPT icmp — 0.0.0.0/0 0.0.0.0/0
3 ACCEPT all – 0.0.0.0/0 0.0.0.0/0
4 ACCEPT tcp – 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
5 REJECT all – 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
1 DOCKER all – 0.0.0.0/0 0.0.0.0/0
2 ACCEPT all – 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
3 ACCEPT all – 0.0.0.0/0 0.0.0.0/0
4 ACCEPT all – 0.0.0.0/0 0.0.0.0/0
5 REJECT all – 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
如果在node上的iptables规则如上所示。
解决办法:
- 测试环境:iptables -D INPUT 5 && iptables -D FORWARD 5
- 生产环境:允许三个网段通过
- node的IP段
- 容器的Ip段
- 内部service的IP段
10、Docker官网的留言板例子:guestbook页面 出错,原因可能是js地址被墙
解决办法:
1、进入容器
PID=$(docker inspect –format {{.State.Pid}} <容器id>)
nsenter –target $PID –mount –uts –ipc –net –pid
2、Debian安装nano编辑器
apt-get install nano -y
3、修改/var/www/html/index.html
将//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css
修改为//cdn.bootcss.com/bootstrap/3.1.1/css/bootstrap.min.css
将https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js
修改为//cdn.bootcss.com/angular.js/1.2.12/angular.min.js
PS:CTRL+O回车保存,CTRL+X退出
4、重启服务
apache2-foreground
11、在利用yaml文件创建Pod过程中,报“Error from server:the server could not find the requested resource”
这个问题最坑,原因是Kubernetes版本太低,虽然node节点的状态显示是Ready,但无法创建Pod。
伴随现象:在描述节点状态时,显示如下,正常的是没有红色方框部分。
而且显示的版本信息如下:
注意:该版本信息却与Kubernetes官方提供的yum源中的版本信息吻合:http://cbs.centos.org/repos/virt7-testing/x86_64/os/Packages/
而最新的版本信息为:
Kubelet Version: v1.0.3.34+b9a88a7d0e357b
问题原因:
用了CentOS自带光盘作为本地yum源,而删除了CentOS自带的网络yum源的配置文件
解决方法:
使用CentOS自带的网络yum源的配置文件。
12、kube-apiserver.service启动异常,查看错误日志,发现类似如下报错
Failed to list *api.Namespace: Get http://0.0.0.0:8080/api/v1/namespaces: dial tcp 0.0.0.0:8080: connection refused
Failed to list *api.LimitRange: Get http://0.0.0.0:8080/api/v1/limitranges: dial tcp 0.0.0.0:8080: connection refused
解决办法:
尝试单独多重启etcd试试,直至各个服务都正常。
13、无法创建任何资源,如发现如下报错
failed to find fit for pod redis-master-1nd8y on node centos-minion01: MatchNodeSelector
解决办法:
检查yaml文件是否包含nodeSelector字段,而这个字段标签是否正确设置。
六、附录
附1:解析kube-proxy之iptables
本文出自:http://blog.liuker.cn/index.php/docker/32.html
当创建了service之后,就可以对内/外提供服务。那么其具体是通过什么原理来实现的呢?仔细观察node上的iptables会发现其中的奥妙。
会在nat表里生成4个chain
KUBE-PORTALS-CONTAINER:主要是处理所有service对象的cluster IP和port到kube-proxy本地端口的映射
KUBE-PORTALS-HOST:同上类似,只不过此为针对node本地进程,上条为针对容器进程。
KUBE-NODEPORT-CONTAINER:主要是处理所有service对象的NodePort类型的cluster IP和port到kube-proxy本地端口的映射
KUBE-NODEPORT-HOST:同上类似,只不过此为针对node本地进程,上条为针对容器进程。
以service默认的ClusterIP方式为例:
创建service以后,kube-proxy会自动在集群里的node上创建以下两条规则:
-A KUBE-PORTALS-CONTAINER -d 10.254.217.168/32 -p tcp -m comment –comment “default/frontend:” -m tcp –dport 80 -j REDIRECT –to-ports 45587
解释:10.254.217.168是kubernetes分配给当前service的全局唯一地址,80为service定义的端口,45587为kube-proxy分配到本机的随机端口。意思是本地容器到10.254.217.168:8080的流量重定向到45587端口
-A KUBE-PORTALS-HOST -d 10.254.217.168/32 -p tcp -m comment –comment “default/frontend:” -m tcp –dport 80 -j DNAT –to-destination 192.168.1.124:45587
解释:本机到10.254.217.168:8080的流量重定向到45587端口
如果是NodePort方式,还会额外生成两条:
-A KUBE-NODEPORT-CONTAINER -p tcp -m comment –comment “default/frontend:” -m tcp –dport 30002 -j REDIRECT –to-ports 45587
解释:本地容器访问本地30002端口的流量重定向到45587端口
-A KUBE-NODEPORT-HOST -p tcp -m comment –comment “default/frontend:” -m tcp –dport 30002 -j DNAT –to-destination 192.168.1.124:45587
解释:本地进程访问本地30002端口的流量重定向到45587端口
见下图:
流程解析:(以NodePort为例)
1、外部访问service 192.168.1.124:30002,然后根据iptables的规则,重定向到45587。外部client启动随机端口与45587连接。
tcp6 0 0 192.168.1.124:45587 192.168.1.121:35845 ESTABLISHED 13101/kube-proxy
2、kube-proxy会在本机启动一个随机端口,与service分配的pod完成连接。
tcp 0 0 192.168.1.124:40614 172.18.0.9:80 ESTABLISHED 13101/kube-proxy
node相当于一个反向代理的意思
外部client<———>node<———>service(pod)
转载自:靠谱运维 » Docker集群管理之Kubernetes
欢迎关注技术公众号:架构师成长营