共计 13887 个字符,预计需要花费 35 分钟才能阅读完成。
一、前言
Kubernetes 是 Google 开源的容器集群管理系统,基于 Docker 构建一个容器的调度服务,提供资源调度、均衡容灾、服务注册、动态扩缩容等功能套件,目前 CentOS yum 源上最新版本为 1.4。本文介绍如何基于 CentOS 7.3 构建 Kubernetes 平台,在正式介绍之前,大家有必要先理解 Kubernetes 几个核心概念及其承担的功能。以下为 Kubernetes 的架构设计图:
1. Pods
在 Kubernetes 系统中,调度的最小颗粒不是单纯的容器,而是抽象成一个 Pod,Pod 是一个可以被创建、销毁、调度、管理的最小的部署单元。比如一个或一组容器。
2. Replication Controllers
Replication Controller 是 Kubernetes 系统中最有用的功能,实现复制多个 Pod 副本,往往一个应用需要多个 Pod 来支撑,并且可以保证其复制的副本数,即使副本所调度分配的主宿机出现异常,通过 Replication Controller 可以保证在其它主宿机启用同等数量的 Pod。Replication Controller 可以通过 repcon 模板来创建多个 Pod 副本,同样也可以直接复制已存在 Pod,需要通过 Label selector 来关联。
3. Services
Services 是 Kubernetes 最外围的单元,通过虚拟一个访问 IP 及服务端口,可以访问我们定义好的 Pod 资源,目前的版本是通过 iptables 的 nat 转发来实现,转发的目标端口为 Kube_proxy 生成的随机端口,目前只提供 GOOGLE 云上的访问调度,如 GCE。如果与我们自建的平台进行整合?请关注下篇《kubernetes 与 HECD 架构的整合》文章。
4. Labels
Labels 是用于区分 Pod、Service、Replication Controller 的 key/value 键值对,仅使用在 Pod、Service、Replication Controller 之间的关系识别,但对这些单元本身进行操作时得使用 name 标签。
5. Proxy
Proxy 不但解决了同一主宿机相同服务端口冲突的问题,还提供了 Service 转发服务端口对外提供服务的能力,Proxy 后端使用了随机、轮循负载均衡算法。
6. Deployment
Kubernetes Deployment 提供了官方的用于更新 Pod 和 Replica Set(下一代的 Replication Controller)的方法 Kubernetes Deployment 提供了官方的用于更新 Pod 和 Replica Set(下一代的 Replication Controller)的方法,您可以在 Deployment 对象中只描述您所期望的理想状态(预期的运行状态),Deployment 控制器为您将现在的实际状态转换成您期望的状态,例如,您想将所有的 webapp:v1.0.9 升级成 webapp:v1.1.0,您只需创建一个 Deployment,Kubernetes 会按照 Deployment 自动进行升级。现在,您可以通过 Deployment 来创建新的资源(pod,rs,rc),替换已经存在的资源等。
Deployment 集成了上线部署、滚动升级、创建副本、暂停上线任务,恢复上线任务,回滚到以前某一版本(成功 / 稳定)的 Deployment 等功能,在某种程度上,Deployment 可以帮我们实现无人值守的上线,大大降低我们的上线过程的复杂沟通、操作风险
二、Kubernetes 集群部署
- 平台版本说明
节点 | IP 地址 | CPU | 内存 |
---|---|---|---|
master | 192.168.3.51 | 4 核 | 4GB |
etcd | 192.168.3.52 | 1 核 | 2GB |
node1 | 192.168.3.53 | 1 核 | 2GB |
node2 | 192.168.3.54 | 1 核 | 2GB |
-
系统初始化安装(所有主机)- 选择【最小化安装】, 然后 yum update, 升级到最新版本
yum update
yum install -y etcd kubernetes ntp flannel
-
更改 Hostname 为 master、etcd、node1、node2,配置 IP 地址, 配置 4 台测试机的 /etc/hosts 文件
[root@master ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.3.51 master 192.168.3.52 etcd 192.168.3.53 node1 192.168.3.54 node2 [root@master ~]#
- 时间校对
ntpdate ntp1.aliyun.com
hwclock -w
- 关闭 CentOS7 自带的防火墙服务
systemctl disable firewalld; systemctl stop firewalld
-
配置 etcd 服务器
[root@etcd ~]# grep -v '^#' /etc/etcd/etcd.conf ETCD_NAME=default ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_CLIENT_URLS="http://localhost:2379,http://192.168.3.52:2379" ETCD_ADVERTISE_CLIENT_URLS="http://192.168.3.52:2379" [root@etcd ~]# 启动服务 systemctl start etcd systemctl enable etcd 检查 etcd cluster 状态 [root@etcd ~]# etcdctl cluster-health member 8e9e05c52164694d is healthy: got healthy result from http://192.168.3.52:2379 cluster is healthy [root@etcd ~]# 检查 etcd 集群成员列表,这里只有一台 [root@etcd ~]# etcdctl member list 8e9e05c52164694d: name=default peerURLs=http://localhost:2380 clientURLs=http://192.168.3.52:2379 isLeader=true [root@etcd ~]# 配置防火墙 firewall-cmd --zone=public --add-port=2379/tcp --permanent firewall-cmd --zone=public --add-port=2380/tcp --permanent firewall-cmd --reload firewall-cmd --list-all
-
配置 master 服务器
1) 配置 kube-apiserver 配置文件 [root@master ~]# grep -v '^#' /etc/kubernetes/config KUBE_LOGTOSTDERR="--logtostderr=true" KUBE_LOG_LEVEL="--v=0" KUBE_ALLOW_PRIV="--allow-privileged=false" KUBE_MASTER="--master=http://192.168.3.51:8080" [root@master ~]# [root@master ~]# grep -v '^#' /etc/kubernetes/apiserver [root@master ~]# grep -v '^#' /etc/kubernetes/apiserver KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0" KUBE_ETCD_SERVERS="--etcd-servers=http://192.168.3.52:2379" KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16" KUBE_ADMISSION_CONTROL="--admission-control=AlwaysAdmit" KUBE_API_ARGS="" [root@master ~]# 2) 配置 kube-controller-manager 配置文件 [root@master ~]# grep -v '^#' /etc/kubernetes/controller-manager KUBE_CONTROLLER_MANAGER_ARGS="" [root@master ~]# 3) 配置 kube-scheduler 配置文件 [root@master ~]# grep -v '^#' /etc/kubernetes/scheduler KUBE_SCHEDULER_ARGS="--address=0.0.0.0" [root@master ~]# 4) 启动服务 for SERVICES in kube-apiserver kube-controller-manager kube-scheduler do systemctl restart SERVICES done
-
配置 node1 节点服务器
1) 配置 etcd [root@etcd ~]# etcdctl set /k8s/network/config '{"Network":"10.255.0.0/16"}' {"Network": "10.255.0.0/16"} [root@etcd ~]# etcdctl get /k8s/network/config {"Network": "10.255.0.0/16"} [root@etcd ~]# 2) 配置 node1 网络,本实例采用 flannel 方式来配置,如需其他方式,请参考 Kubernetes 官网。[root@node1 ~]# grep -v '^#' /etc/sysconfig/flanneld FLANNEL_ETCD_ENDPOINTS="http://192.168.3.52:2379" FLANNEL_ETCD_PREFIX="/k8s/network" FLANNEL_OPTIONS="--iface=ens33" [root@node1 ~]# 备注:ens33 用 ip a 命令获取,根据实际情况更改 3) 配置 node1 kube-proxy [root@node1 ~]# grep -v '^#' /etc/kubernetes/config KUBE_LOGTOSTDERR="--logtostderr=true" KUBE_LOG_LEVEL="--v=0" KUBE_ALLOW_PRIV="--allow-privileged=false" KUBE_MASTER="--master=http://192.168.3.51:8080" [root@node1 ~]# [root@node1 ~]# grep -v '^#' /etc/kubernetes/proxy KUBE_PROXY_ARGS="--bind=address=0.0.0.0" [root@node1 ~]# 4) 配置 node1 kubelet [root@node1 ~]# grep -v '^#' /etc/kubernetes/kubelet KUBELET_ADDRESS="--address=127.0.0.1" KUBELET_HOSTNAME="--hostname-override=node1" KUBELET_API_SERVER="--api-servers=http://192.168.3.51:8080" KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.RedHat.com/rhel7/pod-infrastructure:latest" KUBELET_ARGS="" [root@node1 ~]# 5) 启动 node1 服务 for SERVICES in flanneld kube-proxy kubelet; do systemctl restart $SERVICES systemctl enable $SERVICES systemctl status $SERVICES done
-
配置 node2 节点服务器
1) 配置 node2 网络,本实例采用 flannel 方式来配置,如需其他方式,请参考 Kubernetes 官网。[root@node2 ~]# grep -v '^#' /etc/sysconfig/flanneld FLANNEL_ETCD_ENDPOINTS="http://192.168.3.52:2379" FLANNEL_ETCD_PREFIX="/k8s/network" FLANNEL_OPTIONS="--iface=eno16777736" [root@node2 ~]# 备注:eno16777736 用 ip a 命令获取,根据实际情况更改 2) 配置 node2 kube-proxy [root@node2 ~]# grep -v '^#' /etc/kubernetes/config KUBE_LOGTOSTDERR="--logtostderr=true" KUBE_LOG_LEVEL="--v=0" KUBE_ALLOW_PRIV="--allow-privileged=false" KUBE_MASTER="--master=http://192.168.3.51:8080" [root@node2 ~]# [root@node2 ~]# grep -v '^#' /etc/kubernetes/proxy KUBE_PROXY_ARGS="--bind-address=0.0.0.0" [root@node2 ~]# 3) 配置 node2 kubelet [root@node2 ~]# grep -v '^#' /etc/kubernetes/kubelet KUBELET_ADDRESS="--address=127.0.0.1" KUBELET_HOSTNAME="--hostname-override=node1" KUBELET_API_SERVER="--api-servers=http://192.168.3.51:8080" KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest" KUBELET_ARGS="" [root@node2 ~]# 4) 启动 node2 服务 for SERVICES in flanneld kube-proxy kubelet docker; do systemctl restart $SERVICES systemctl enable $SERVICES systemctl status $SERVICES done
-
至此,整个 Kubernetes 集群搭建完毕
[root@master ~]# kubectl get nodes NAME STATUS AGE node1 Ready 34m node2 Ready 2m [root@master ~]#
三、在上面的集群上搭建基于 Redis 和 docker 的留言簿案例
1、启动 Redis master
使用 deployment 确保只有一个 pod 在运行(当某个节点 down 了,deploy 会在另一个健康的 node 启动 redis master),但可能会有数据丢失。
[root@master guestbook]# kubectl create -f redis-master-deployment.yaml deployment "redis-master" created [root@master guestbook]# [root@master guestbook]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE redis-master 1 1 1 1 3m [root@master guestbook]# [root@master guestbook]# kubectl get pods NAME READY STATUS RESTARTS AGE redis-master-517881005-c3qek 1/1 Running 0 4m [root@master guestbook]#
2、启动 master service
一个 kubernetes service 会对一个或多个 Container 进行负载均衡,这是通过我们上面 redis-master 中定义的 labels 元数据实现的,值得注意的是,在 redis 中只有一个 master,但是我们依然为它创建一个 service,这是因为这样我们就能使用一个 elastic IP 来路由到具体某一个 master。
kubernetes 集群中的 service 是通过 container 中的环境变量实现服务发现的,service 基于 pod label 实现 container 的负载均衡。
在第一步中创建的 pod 包含了一个 label“name=redis-master”,service 的 selector 字段决定了 service 将流量转发给哪个 pod,port 和 targetPort 信息定义了 service proxy 运行在什么端口。
[root@master guestbook]# kubectl create -f redis-master-service.yaml service "redis-master" created [root@master guestbook]# root@master guestbook]# kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 10.254.0.1 443/TCP 33m redis-master 10.254.203.144 6379/TCP 58s [root@master guestbook]#
上面的运行成功后,所有 pods 都能发现 redis master 运行在 6379 端口,从 salve 到 master 流量走向会有以下两步:
1) 一个 redis slave 会连接到 redis master service 的 port 上
2) 流量会从 service 节点上的 port 到 targetPort, 如果 targetPort 未指定,默认和 port 一致
3、启动 replicated slave pod
虽然 redis master 是一个单独的 pod,redis slaves 是一个 replicated pod,在 Kubernetes 中,一个 Replication Controller 负责管理一个 replicated pod 的多个实例,RC 会自动拉起 down 掉的 replica(可以通过杀死 docker 进程方式简单测试)
[root@master guestbook]# kubectl create -f redis-slave-deployment.yaml deployment "redis-slave" created [root@master guestbook]# [root@master guestbook]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE redis-master 1 1 1 1 17m redis-slave 2 2 2 2 24s [root@master guestbook]# [root@master guestbook]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE redis-master-517881005-c3qek 1/1 Running 0 18m 10.255.73.2 node2 redis-slave-1885102530-brg9b 1/1 Running 0 1m 10.255.73.3 node2 redis-slave-1885102530-o8y5p 1/1 Running 0 1m 10.255.70.2 node1 [root@master guestbook]# 可以看到一个 master pod 和两个 slave pod
4、启动 slave service
和 master 一样,我们希望有一个代理服务连接到 redis slave,除了服务发现之外,slave service 还为 web app client 提供了透明代理。
这次 service 的 selector 是 name=redis-slave,我们可以方便的使用 kubectl get services -l“label=value”命令来定位这些服务
[root@master guestbook]# kubectl create -f redis-slave-service.yaml
service“redis-slave”created
[root@master guestbook]#
[root@master guestbook]# kubectl get svc -o wide
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes 10.254.0.1 443/TCP 44m
redis-master 10.254.203.144 6379/TCP 12m app=redis,role=master,tier=backend
redis-slave 10.254.0.214 6379/TCP 38s app=redis,role=slave,tier=backend
[root@master guestbook]#
5、创建 frontend pod
这是一个简单的 PHP 服务,用来和 master service(写请求)或 slave service(读请求)交互
[root@master guestbook]# kubectl create -f frontend-deployment.yaml deployment "frontend" created [root@master guestbook]# [root@master guestbook]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE frontend 3 3 3 2 13s redis-master 1 1 1 1 22m redis-slave 2 2 2 2 5m [root@master guestbook]# [root@master guestbook]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE frontend-941252965-8rvrb 1/1 Running 0 1m 10.255.73.4 node2 frontend-941252965-ka3vd 1/1 Running 0 1m 10.255.70.3 node1 frontend-941252965-qqamp 1/1 Running 0 1m 10.255.70.4 node1 redis-master-517881005-c3qek 1/1 Running 0 24m 10.255.73.2 node2 redis-slave-1885102530-brg9b 1/1 Running 0 7m 10.255.73.3 node2 redis-slave-1885102530-o8y5p 1/1 Running 0 7m 10.255.70.2 node1 [root@master guestbook]# 可以看到一个 redis master,两个 redis slave 和三个 frontend pods
6、创建 guestbook service
和其他 service 一样,你可以创建一个 service 管理 frontend pods
[root@master guestbook]# kubectl create -f frontend-service.yaml service "frontend" created [root@master guestbook]# [root@master guestbook]# kubectl get svc -o wide NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR frontend 10.254.18.215 80/TCP 44s app=guestbook,tier=frontend kubernetes 10.254.0.1 443/TCP 50m redis-master 10.254.203.144 6379/TCP 18m app=redis,role=master,tier=backend redis-slave 10.254.0.214 6379/TCP 6m app=redis,role=slave,tier=backend [root@master guestbook]#
我们可以通过 frontend service(10.254.18.215)访问 pods
7、外部网络访问 guestbook
http://192.168.3.54:30001 可以直接访问了
[root@node2 ~]# curl http://192.168.3.54:30001
Guestbook
Guestbook
Submit
{{msg}}
[root@node2 ~]#
附: 本案例用到的 6 个.yaml 文件
1、redis-master-deployment.yaml
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: redis-master # these labels can be applied automatically # from the labels in the pod template if not set # labels: # app: redis # role: master # tier: backend spec: # this replicas value is default # modify it according to your case replicas: 1 # selector can be applied automatically # from the labels in the pod template if not set # selector: # matchLabels: # app: guestbook # role: master # tier: backend template: metadata: labels: app: redis role: master tier: backend spec: containers: - name: master image: redis resources: requests: cpu: 100m memory: 100Mi ports: - containerPort: 6379
2、redis-master-service.yaml
apiVersion: v1 kind: Service metadata: name: redis-master labels: app: redis role: master tier: backend spec: ports: # the port that this service should serve on - port: 6379 targetPort: 6379 selector: app: redis role: master tier: backend
3、redis-slave-deployment.yaml
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: redis-slave # these labels can be applied automatically # from the labels in the pod template if not set # labels: # app: redis # role: slave # tier: backend spec: # this replicas value is default # modify it according to your case replicas: 2 # selector can be applied automatically # from the labels in the pod template if not set # selector: # matchLabels: # app: guestbook # role: slave # tier: backend template: metadata: labels: app: redis role: slave tier: backend spec: containers: - name: slave image: kubeguide/guestbook-redis-slave resources: requests: cpu: 100m memory: 100Mi env: - name: GET_HOSTS_FROM value: env # If your cluster config does not include a dns service, then to # instead access an environment variable to find the master # service's host, comment out the'value: dns' line above, and # uncomment the line below. # value: env ports: - containerPort: 6379
4、redis-slave-service.yaml
apiVersion: v1 kind: Service metadata: name: redis-slave labels: app: redis role: slave tier: backend spec: ports: # the port that this service should serve on - port: 6379 selector: app: redis role: slave tier: backend
5、frontend-deployment.yaml
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: frontend # these labels can be applied automatically # from the labels in the pod template if not set # labels: # app: guestbook # tier: frontend spec: # this replicas value is default # modify it according to your case replicas: 3 # selector can be applied automatically # from the labels in the pod template if not set # selector: # matchLabels: # app: guestbook # tier: frontend template: metadata: labels: app: guestbook tier: frontend spec: containers: - name: php-redis image: kubeguide/guestbook-php-frontend resources: requests: cpu: 100m memory: 100Mi env: - name: GET_HOSTS_FROM value: env # If your cluster config does not include a dns service, then to # instead access environment variables to find service host # info, comment out the 'value: dns' line above, and uncomment the # line below. # value: env ports: - containerPort: 80
6、frontend-service.yaml
apiVersion: v1 kind: Service metadata: name: frontend labels: app: guestbook tier: frontend spec: # if your cluster supports it, uncomment the following to automatically create # an external load-balanced IP for the frontend service. # type: LoadBalancer type: NodePort ports: # the port that this service should serve on - port: 80 nodePort: 30001 selector: app: guestbook tier: frontend
Docker 中部署 Kubernetes http://www.linuxidc.com/Linux/2016-07/133020.htm
Kubernetes 集群部署 http://www.linuxidc.com/Linux/2015-12/125770.htm
OpenStack, Kubernetes, Mesos 谁主沉浮 http://www.linuxidc.com/Linux/2015-09/122696.htm
Kubernetes 集群搭建过程中遇到的问题及解决 http://www.linuxidc.com/Linux/2015-12/125735.htm
Kubernetes 集群部署 http://www.linuxidc.com/Linux/2015-12/125770.htm
Ubuntu 16.04 下安装搭建 Kubernetes 集群环境 http://www.linuxidc.com/Linux/2017-02/140555.htm
Kubernetes 的详细介绍 :请点这里
Kubernetes 的下载地址 :请点这里
本文永久更新链接地址 :http://www.linuxidc.com/Linux/2017-02/140723.htm