1、OpenStack 介绍
OpenStack是一个由美国国家航空航天局(National Aeronautics and Space Administration,NASA)和Rackspace合作研究并发起的,以Apache许可证授权的自由软件和开放源代码项目,OpenStack是一个开源的云计算管理平台项目,由几个主要的组件组合起来完成具体工作。OpenStack支持几乎所有类型的云环境,项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenStack通过各种互补的服务提供了基础设施即服务(Infrastructure as a Service,IaaS)的解决方案,每个服务提供API以进行集成,当然除了Iaas解决方案,还有主流的平台即服务(Platform-as-a-Service,PaaS)和软件即服务(Software-as-a-Service,SaaS),三者区别如图所示:
2、Kubernetes 介绍
2.1 概念
Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括部署,调度和节点集群间扩展。可以将Docker看成Kubernetes内部使用的低级别组件。Kubernetes不仅支持Docker,还支持其他的容器技术Rocket、KVM软件服务,使用Kubernetes可以实现如下功能:
自动化容器的部署和复制;
随时扩展或收缩容器规模;
将容器组织成组,并且提供容器间的负载均衡;
很容易地升级应用程序容器的新版本;
提供容器弹性,如果容器失效就替换它等。
2.2 Kubernetes平台组件概念
Kubernetes集群中主要存在两种类型的节点:Master、Minion节点,Master节点主要是用于管理整个集群所有的Minion节点,对整个集群的资源进行调度、控制,提供统一入口API,所有对集群的操作指令均要通过API接口授权方可。Minion节点为运行 Docker容器的节点,负责和节点上运行的 Docker 进行交互,并且提供了代理功能。
Master主控节点服务:
Apiserver:用户和 kubernetes 集群交互的入口,封装了核心对象的增删改查操作,提供了 RESTFul 风格的 API 接口,通过etcd来实现持久化并维护对象的一致性。Apiserver服务非常重要,出现异常,所有的操作均无法执行。
Scheduler:负责集群资源的调度和管理,例如当有 pod 异常退出需要重新分配机器时,scheduler 通过一定的调度算法从而找到最合适的节点,将新的任务分配到其他节点上。
Controller-manager:集群内部的管理控制中心,负责集群内的Node、Pod副本、服务端点(Endpoint)、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)的管理,当某个Node意外宕机时,Controller Manager会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。
Minion计算节点服务:
Kubelet:主要是用于和节点上Docker引擎服务做交互、控制,调用Docker引擎服务:创建、删除、部署、更新、启动Docker容器,还可以监控每个容器的资源(CPU、MEM、DISK)使用情况。
Proxy:负责为 pod 提供代理功能,会定期从 etcd 获取 service 信息。对外提供统一的访问入口,并根据 service 信息通过修改 iptables 来实现流量转发(最初的版本是直接通过程序提供转发功能,效率较低。),将流量转发到要访问的 pod 所在的节点上去。
其他服务:
Etcd:etcd 是一个分布式一致性k-v存储系统数据库,可用于服务注册发现与共享配置数据库,用来存储kubernetes的信息(容器的IP、节点IP、分组、业务组、负载均衡配置等)。
Flannel:Flannel是CoreOS 团队针对 Kubernetes 设计的一个覆盖网络(Overlay Network)工具,Flannel 目的就是为集群中的所有节点重新规划 IP 地址的使用规则,从而使得不同节点上的容器能够获得同属一个内网且不重复的 IP 地址,并让属于不同节点上的容器能够直接通过内网 IP 通信,让使用人员无需关注网络,轻松实现云计算平台内部通信。
3、Kubernetes平台工作原理
Kubernetes集群是一组节点,这些节点可以是物理服务器或者虚拟机,在其上安装Kubernetes平台。下图为了强调核心概念有所简化:
4、部署
准备三台机器
master 10.0.0.147
etcd 10.0.0.149
minion 10.0.0.150
4.1 Etcd 部署
[root@localhost ~]# yum install -y etcd
[root@localhost ~]# vim /etc/etcd/etcd.conf
# ETCD数据目录
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
# ETCD监听的数据端口2379
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://10.0.0.149:2379"
# NAME节点名称
ETCD_NAME="default"
# ETCD集群之间数据共享,对外宣告的URL+2379端口
ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379,http://10.0.0.149:2379"
[root@localhost ~]# systemctl start etcd
4.2 Master 部署
[root@localhost ~]# yum install -y kubernetes-master flannel
[root@localhost ~]# cd /etc/kubernetes/
[root@localhost kubernetes]# ll
总用量 16
-rw-r--r-- 1 root root 931 4月 22 20:56 apiserver
-rw-r--r-- 1 root root 656 4月 22 20:57 config
-rw-r--r-- 1 root root 189 7月 3 2017 controller-manager
-rw-r--r-- 1 root root 111 7月 3 2017 scheduler
Apiserver : 用户和整个K8S集群交互操作的统一入口,所有的操作、配置、资源申请都需经过Apiserver接口;
config : K8S Master主配置文件,指定Master Apiserver的IP+端口;
Controller-manager :K8S副本控制配置文件,用于控制后期容器资源副本数,时刻保障副本的正常运行;
Scheduler :K8S节点资源调度配置文件,用于调度和计算节点的可用资源,将资源申请需求进行调度和分配。
[root@localhost kubernetes]# vim apiserver
# Apiserver监听地址
KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"
# Apiserver监听端口
KUBE_API_PORT="--port=8080"
#连接ETCD配置数据库
KUBE_ETCD_SERVERS="--etcd-servers=http://10.0.0.149:2379"
# 指定Service Cluster VIP地址网段
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"
# 设置K8S管理控制功能,去除默认的ServiceAccount认证模块
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"
# K8S API额外参数设置
KUBE_API_ARGS=""
[root@localhost kubernetes]# vim config
# 开启K8S日志功能,/var/log/message
KUBE_LOGTOSTDERR="--logtostderr=true"
# K8S日志记录模式Debug,0表示debug
KUBE_LOG_LEVEL="--v=0"
# 是否开启超级特权模式,false表示未开启
KUBE_ALLOW_PRIV="--allow-privileged=false"
# 指定K8S Master的Apiserver的IP+8080端口
KUBE_MASTER="--master=http://10.0.0.147:8080"
启动服务
[root@localhost kubernetes]# systemctl start kube-apiserver
[root@localhost kubernetes]# systemctl start kube-controller-manager
[root@localhost kubernetes]# systemctl start kube-scheduler
[root@localhost kubernetes]# ps -ef|grep kube
kube 9196 1 2 16:40 ? 00:00:06 /usr/bin/kube-apiserver --logtostderr=true --v=0 --etcd-servers=http://10.0.0.149:2379 --insecure-bind-address=0.0.0.0 --allow-privileged=false --service-cluster-ip-range=10.254.0.0/16 --admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota
kube 9221 1 3 16:40 ? 00:00:05 /usr/bin/kube-controller-manager --logtostderr=true --v=0 --master=http://10.0.0.147:8080
kube 9270 1 0 16:40 ? 00:00:01 /usr/bin/kube-scheduler --logtostderr=true --v=0 --master=http://10.0.0.147:8080
root 9415 6551 0 16:43 pts/0 00:00:00 grep --color=auto kube
4.3 Minion 部署
[root@localhost ~]# yum install -y kubernetes-node docker flannel *rhsm*
[root@localhost ~]# cd /etc/kubernetes/
[root@localhost kubernetes]# ll
总用量 12
-rw-r--r-- 1 root root 656 4月 22 21:24 config
-rw-r--r-- 1 root root 615 4月 22 21:32 kubelet
-rw-r--r-- 1 root root 103 7月 3 2017 proxy
Config :K8S Node主配置文件,主要是指定Apiserver的IP和端口,自身的日志开启、日志级别设置;
Kubelet :Kubelet用于跟本地的Docker引擎服务通信的,负责连接、管理、控制Docker,给Docker引擎发送任务,管理Docker容器(启动、停止、删除、重启等);
Proxy :Proxy是用于实现K8S代理转发容器端口,可以实现Forward或者NAT地址转换,用于后期Service服务访问、感知的。
[root@localhost kubernetes]# vim config
# 开启K8S日志功能,/var/log/message
KUBE_LOGTOSTDERR="--logtostderr=true"
# K8S日志记录模式Debug,0表示debug
KUBE_LOG_LEVEL="--v=0"
# 是否开启超级特权模式,false表示未开启
KUBE_ALLOW_PRIV="--allow-privileged=false"
# 指定K8S Master的Apiserver的IP+8080端口
KUBE_MASTER="--master=http://10.0.0.147:8080"
[root@localhost kubernetes]# vim kubelet
# kubelet监听地址
KUBELET_ADDRESS="--address=0.0.0.0"
# The port for the info server to serve on
# KUBELET_PORT="--port=10250"
# Kubelet监听主机
KUBELET_HOSTNAME="--hostname-override=10.0.0.150"
# 指定Apiserver的IP和8080端口
KUBELET_API_SERVER="--api-servers=http://10.0.0.147:8080"
# 指定K8S POD基础镜像名称
KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"
# 指定kubelet的额外参数
KUBELET_ARGS=""
启动
[root@localhost kubernetes]# systemctl start kubelet
[root@localhost kubernetes]# systemctl start kube-proxy
[root@localhost kubernetes]# ps -ef|grep kube
root 7187 1 10 17:00 ? 00:00:03 /usr/bin/kubelet --logtostderr=true --v=0 --api-servers=http://10.0.0.147:8080 --address=0.0.0.0 --hostname-override=10.0.0.150 --allow-privileged=false --pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest
root 7275 1 5 17:00 ? 00:00:00 /usr/bin/kube-proxy --logtostderr=true --v=0 --master=http://10.0.0.147:8080
root 7437 6666 0 17:00 pts/0 00:00:00 grep --color=auto kube
Master 端获取 Nodes
[root@localhost kubernetes]# kubectl get nodes
NAME STATUS AGE
10.0.0.150 Ready 2m
# 删除节点命令,重启Minion端kubelet、kube-proxy即可重新注册进来
[root@localhost kubernetes]# kubectl delete nodes/10.0.0.150
node "10.0.0.150" deleted
[root@localhost kubernetes]# kubectl get nodes
No resources found.
4.4 Falanel 部署
Flannel目的就是为集群中的所有节点重新规划 IP 地址的使用规则,从而使得不同节点上的容器能够获得同属一个内网且不重复的 IP 地址,并让属于不同节点上的容器能够直接通过内网 IP 通信。
Master 端和 Minion 端分别修改配置
[root@localhost ~]# vim /etc/sysconfig/flanneld
# 指定ETCD配置数据库的IP和2379端口
FLANNEL_ETCD_ENDPOINTS="http://10.0.0.149:2379"
# 指定ETCD配置数据库的KEY,需要提前创建K-V
FLANNEL_ETCD_PREFIX="/atomic.io/network"
# Flannel额外参数配置;
# FLANNEL_OPTIONS=""
ETCD 机器创建Flannel网络所需的K-V键值对
# 创建K-V键值对
[root@localhost ~]# etcdctl mk /atomic.io/network/config '{"Network":"172.17.0.0/16"}'
# 查看ETCD键树
[root@localhost ~]# etcdctl ls /atomic.io
/atomic.io/network
[root@localhost ~]# etcdctl ls /atomic.io/network
/atomic.io/network/config
/atomic.io/network/subnets
# 获取KEY值
[root@localhost ~]# etcdctl get /atomic.io/network/config
{"Network":"172.17.0.0/16"}
Master端启动 Flannel,注意要先启动Flannel再启动docker
[root@localhost kubernetes]# systemctl start flanneld
[root@localhost kubernetes]# systemctl start docker
[root@localhost kubernetes]# ps -ef|grep docker
root 7045 1 0 17:00 ? 00:00:01 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json --selinux-enabled --log-driver=journald --signature-verification=false --storage-driver overlay2
root 7050 7045 0 17:00 ? 00:00:00 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc --runtime-args --systemd-cgroup=true
root 8661 6666 0 17:02 pts/0 00:00:00 grep --color=auto docker
[root@localhost ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.0.159 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::20ff:bdcd:8409:96e9 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:b7:36:91 txqueuelen 1000 (Ethernet)
RX packets 53149 bytes 25071997 (23.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 54081 bytes 18745700 (17.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1472
inet 172.17.19.0 netmask 255.255.0.0 destination 172.17.19.0
inet6 fe80::4ab7:5719:dd15:84f9 prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1 bytes 48 (48.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 53265 bytes 14838421 (14.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 53265 bytes 14838421 (14.1 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Monion 端启动 Flannel
[root@localhost kubernetes]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.1.1 netmask 255.255.255.0 broadcast 0.0.0.0
ether 02:42:22:bc:7c:3c txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.0.150 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::996:6962:aea5:f905 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:68:03:e2 txqueuelen 1000 (Ethernet)
RX packets 5503 bytes 2317673 (2.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4861 bytes 1116650 (1.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1472
inet 172.17.1.0 netmask 255.255.0.0 destination 172.17.1.0
inet6 fe80::1dab:3824:50cb:5f46 prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3 bytes 144 (144.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 82 bytes 6818 (6.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 82 bytes 6818 (6.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Master端和 Minion端可以相互PING通
[root@localhost kubernetes]# ping 172.17.19.0
PING 172.17.19.0 (172.17.19.0) 56(84) bytes of data.
64 bytes from 172.17.19.0: icmp_seq=1 ttl=62 time=1.60 ms
64 bytes from 172.17.19.0: icmp_seq=2 ttl=62 time=1.82 ms
[root@localhost ~]# ping 172.17.1.1
PING 172.17.1.1 (172.17.1.1) 56(84) bytes of data.
64 bytes from 172.17.1.1: icmp_seq=1 ttl=62 time=0.908 ms
64 bytes from 172.17.1.1: icmp_seq=2 ttl=62 time=0.830 ms
5、Dashborad UI 界面
K8S默认集群是通过命令行操作的,命令行操作不便于日常的维护和管理,可以引入Dashborad图形界面进行操作、管理。
Minion 端导入镜像
[root@localhost ~]# docker load < pod-infrastructure.tgz
[root@localhost ~]# docker tag $(docker images|grep none|awk '{print $3}') registry.access.redhat.com/rhel7/pod-infrastructure
[root@localhost ~]# docker load < kubernetes-dashboard-amd64.tgz
[root@localhost ~]# docker tag $(docker images|grep none|awk '{print $3}') bestwu/kubernetes-dashboard-amd64:v1.6.3
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.access.redhat.com/rhel7/pod-infrastructure latest 99965fb98423 2 days ago 209 MB
bestwu/kubernetes-dashboard-amd64 v1.6.3 9595afede088 2 days ago 139 MB
Master 端创建dashboard-controller.yaml
[root@localhost ~]# touch dashboard-controller.yaml
[root@localhost ~]# vim dashboard-controller.yaml
# 修改apiserver-host 为本机地址即可
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kubernetes-dashboard
namespace: kube-system
labels:
k8s-app: kubernetes-dashboard
kubernetes.io/cluster-service: "true"
spec:
selector:
matchLabels:
k8s-app: kubernetes-dashboard
template:
metadata:
labels:
k8s-app: kubernetes-dashboard
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ''
scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
spec:
containers:
- name: kubernetes-dashboard
image: bestwu/kubernetes-dashboard-amd64:v1.6.3
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 100m
memory: 50Mi
requests:
cpu: 100m
memory: 50Mi
ports:
- containerPort: 9090
args:
- --apiserver-host=http://10.0.0.147:8080
livenessProbe:
httpGet:
path: /
port: 9090
initialDelaySeconds: 30
timeoutSeconds: 30
Master 端创建dashboard-service.yaml
[root@localhost ~]# vim dashboard-service.yaml
apiVersion: v1
kind: Service
metadata:
name: kubernetes-dashboard
namespace: kube-system
labels:
k8s-app: kubernetes-dashboard
kubernetes.io/cluster-service: "true"
spec:
selector:
k8s-app: kubernetes-dashboard
ports:
- port: 80
targetPort: 9090
创建 Dashboard 图形界面
[root@localhost ~]# kubectl create -f dashboard-service.yaml
service "kubernetes-dashboard" created
[root@localhost ~]# kubectl create -f dashboard-controller.yaml
deployment "kubernetes-dashboard" created
[root@localhost ~]# kubectl get --namespace=kube-system pods
NAME READY STATUS RESTARTS AGE
kubernetes-dashboard-3639120983-mbkdn 1/1 Running 0 25s
访问
http://10.0.0.147:8080/ui 访问UI界面
设置防火墙规则ACCEPT: iptables -P FORWARD ACCEPT
重启docker,docker启动要在flannel之后。
systemctl restart docker