一、Kubernetes基础知识
1、在Kubernete中,Service是分布式集群架构的核心,一个Service对象拥有如下关键特征
- 拥有一个唯一指定的名字。
- 拥有一个虚拟IP和端口号。
- 能够提供某种远程服务能力。
- 被映射到了提供这种服务能力的一组容器应用上。
- Service是从应用视角观察得到的。
2、什么是Pod对象
- 把为Service提供服务的一组进程放入容器中进行隔离,即诞生了Pod对象,每个服务进程都将是Pod中运行的一个容器。
- Kubernete给Pod打上一个标签Label,然后给Service定义了一个标签选择器Label Selector,这样二者就可以建立关联关系了。
- Pod是从系统视角观察得到的。
3、什么是Node
- Pod运行在一个称之为Node的环境中
- Node可以是物理机、虚机或云主机
- 通常在一个Node上运行几百个Pod。
4、什么是Pause容器和业务容器
- 在每个Pod中又运行了一个称之为Pause的特殊容器,而其它容器则属于业务容器。
- 业务容器共享Pause容器的网络栈和Volume挂载卷,因此它们之间的通信和数据交换更为高效。
- 在设计时我们可以充分利用以上特性将一组密切相关的服务进程放入同一个Pod中。
- 需要注意的是,并不是每个Pod和它里面运行的容器都能“映射”到一个Service上。只有那些向外界提供服务的一组Pod才会被这样配置。
5、Kubernete的集群管理
- Kubernete将集群中的机器划分为一个Master节点和一群工作节点(Node);
- 在Master节点上运行着集群管理相关的一组进程kube-apiserver、kube-controller-manager和kube-scheduler 。这些进程实现了整个集群的资源管理、Pod调度、弹性伸缩、安全控制、系统监控和纠错等管理功能,且都是自动完成的。
- Node作为工作节点,运行真正的应用程序。Node上运行着Kubernetes的kublete、kube-proxy服务进程。在Node上Kubernetes管理的最小运行单元是Pod。这些服务进程负责Pod的创建、启动、监控、重启、销毁以及负载均衡服务。
6、RC(Replication Controller),为Kubernetes提供了自动扩容功能的支持。在一个RC定义文件中会包括以下3个信息:
- 目标Pod的定义
- 目标Pod需要运行的副本数量
- 要监控的目标Pod的标签
RC运行机制:
- 在创建好RC后,Kubernetes会通过RC中定义的Label挑选出对应的Pod实例并实时监控其状态和数量。
- 如果实例数量少于定义的副本数量,则会根据RC中定义的Pod模板来创建一个新的Pod,然后将此Pod调度到合适的Node上启动运行,直到Pod实例的数量达到预定目标。
- 使用RC后,服务的扩容就成了简单的修改RC中副本数量的操作了。
二、环境准备
以下实验均是使用CentOS7.4 Minimual版本系统完成。
1、关闭系统防火墙
systemctl disable firewalld
systemctl stop firewalld
2、安装etcd和Kubernetes软件
yum -y install etcd kubernetes
3、按顺序启动所有的服务
systemctl start etcd
systemctl start docker
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl start kubelet
systemctl start kube-proxy
一个单机版的kubernete就安装完成了。
4、创建和启动一个MySQL服务
(1)定义一个RC文件:mysql-rc.yaml
apiVersion: v1
kind: ReplicationController #类型为副本控制器RC
metadata:
name: mysql #RC的名称,全局唯一
spec:
replicas: 1 #POD副本期待数量
selector:
app: mysql #符合目标的Pod拥有此标签
template: #根据此模板创建Pod的副本
metadata:
labels:
app: mysql #Pod副本拥有的标签,对应RC的Selector
spec:
containers: #Pod内容器的定义部分
- name: mysql #容器的名称
image: mysql.io/mysql:latest #容器对应的Docker Image
ports:
- containerPort: 3306 #容器应用监听的端口号
env: #注入容器内的环境变量
- name: MYSQL_ROOT_PASSWORD
value: "123456"
在Master节点执行创建命令:
# kubectl create -f mysql-rc.yaml
replicationcontroller "mysql" created
查看刚刚创建的RC:
# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 1 0 0 26s
查看Pod的创建情况:
# kubectl get pods
NAME READY STATUS RESTARTS AGE
注:在创建Pod实例的过程视宿主机性能差异,有时需要待一会。如果立即查看,会像上面显示的样子,还不会立即有结果。
(2)故障排除1
在等了一会儿后发现仍然查看不到正确的创建Pod的结果,于是查看相关日志tail -200 /var/log/messages,看到下面报错信息。
Feb 18 02:09:53 gqtest kube-controller-manager: I0218 02:09:53.543524 1230 event.go:217] Event(api.ObjectReference{Kind:"ReplicationController", Namespace:"default", Name:"mysql", UID:"8ace1e3a-140d-11e8-961e-0800275f8277", APIVersion:"v1", ResourceVersion:"15425", FieldPath:""}): type: 'Warning' reason: 'FailedCreate' Error creating: No API token found for service account "default", retry after the token is automatically created and added to the service account
属于K8S服务间接口调用授权问题,可以通过以下方法解决:
vi /etc/kubernetes/apiserver
# default admission control policies
# KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota"
再查看Pod创建结果:
# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-mn49n 0/1 ContainerCreating 0 27s
(3)故障排除2
又是等待了好一会儿,一直停滞在ContainerCreating的状态,继续查看日志或者使用以下方法查看Pod创建信息:
# kubectl describe pod mysql
Name: mysql-mn49n
Namespace: default
Node: 127.0.0.1/127.0.0.1
Start Time: Sun, 18 Feb 2018 02:17:26 +0800
Labels: app=mysql
Status: Pending
IP:
Controllers: ReplicationController/mysql
Containers:
mysql:
Container ID:
Image: docker.io/mysql:latest
Image ID:
Port: 3306/TCP
State: Waiting
Reason: ContainerCreating
Ready: False
Restart Count: 0
Volume Mounts: <none>
Environment Variables:
MYSQL_ROOT_PASSWORD: 123456
Conditions:
Type Status
Initialized True
Ready False
PodScheduled True
No volumes.
QoS Class: BestEffort
Tolerations: <none>
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
4m 4m 1 {default-scheduler } Normal Scheduled Successfully assigned mysql-mn49n to 127.0.0.1
4m 1m 5 {kubelet 127.0.0.1} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "POD" with ErrImagePull: "image pull failed for registry.access.redhat.com/rhel7/pod-infrastructure:latest, this may be because there are no credentials on this request. details: (open /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt: no such file or directory)"
4m 3s 16 {kubelet 127.0.0.1} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "POD" with ImagePullBackOff: "Back-off pulling image \"registry.access.redhat.com/rhel7/pod-infrastructure:latest\""
从上面信息中看到,是因为系统中缺少一个文件:/etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt
查看这个文件:
# ls -l /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt
lrwxrwxrwx. 1 root root 27 Feb 17 21:39 /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt -> /etc/rhsm/ca/redhat-uep.pem
可以继续看到上面缺少的是一个符号链接指向的物理文件:/etc/rhsm/ca/redhat-uep.pem
找了一些简单的资料,显示rhsm是redhat用于管理服务注册管理的一个软件包,虽然我们使用的开源CentOS系统,用不到这个文件,但显然K8S对此有依赖。
因此,也安装一个该工具包。
# yum search rhsm
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirrors.shu.edu.cn
* epel: mirrors.ustc.edu.cn
* extras: mirror.bit.edu.cn
* updates: mirror.bit.edu.cn
======================================================================== N/S matched: rhsm ========================================================================
python-rhsm.x86_64 : A Python library to communicate with a Red Hat Unified Entitlement Platform
python-rhsm-certificates.x86_64 : Certificates required to communicate with a Red Hat Unified Entitlement Platform
# yum -y install rhsm
再次查看Pod创建结果,看到创建了一个名为mysql-mn49n的容器,显示状态已经变为了Running:
# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-mn49n 1/1 Running 0 13m
查看产生了哪些新的docker容器:
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f5d627846fe docker.io/mysql:latest "docker-entrypoint.sh" About a minute ago Up About a minute k8s_mysql.162321c7_mysql-mn49n_default_cee70dc4-140e-11e8-9692-0800275f8277_a8673105
1ab87e554d8a registry.access.redhat.com/rhel7/pod-infrastructure:latest "/usr/bin/pod" About a minute ago Up About a minute k8s_POD.1d520ba5_mysql-mn49n_default_cee70dc4-140e-11e8-9692-0800275f8277_896ea006
注:共新建了两个docker容器,其中后面那个显然是K8S用于Pod内部网络和其他基础功能管理使用的一个容器。
(4)为上面的创建服务创建一个与之关联的K8s Service的定义文件
apiVersion: v1
kind: Service #类型为k8s Service
metadata:
name: mysql #该Service的全局唯一名称
spec:
ports:
- port: 3306 #Service提供服务的端口号
selector: #Service对应的Pod拥有这里定义的标签
app: mysql
执行创建命令:
[root@gqtest ~]# kubectl create -f mysql-svc.yaml
service "mysql" created
[root@gqtest ~]# kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.254.0.1 <none> 443/TCP 4h
mysql 10.254.20.191 <none> 3306/TCP 11s
[root@gqtest ~]#
可以看到,mysql服务已经被分配了一个10.154.20.191的cluster ip地址。
这是一个虚地址,k8s集群中其他Pod就可以通过Service的Cluster IP+端口号3306来连接这个mysql服务了。
5、启动Tomcat应用
再创建一个tomcat应用,来访问上一步创建的mysql服务,提供一个简单的web功能。
(1)首先创建tomcat服务使用的RC文件
apiVersion: v1
kind: ReplicationController
metadata:
name: myweb
spec:
replicas: 2 #在这里选择配置成了2个副本
selector:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- name: myweb
image: docker.io/kubeguide/tomcat-app:v1
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_HOST
value: 'mysql'
- name: MYSQL_SERVICE_PORT
value: '3306'
执行创建命令:
# kubectl create -f myweb-rc.yaml
查看结果:
[root@gqtest ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-mn49n 1/1 Running 0 41m
myweb-k6fp0 0/1 ContainerCreating 0 2m
myweb-m9nv9 0/1 ContainerCreating 0 2m
[root@gqtest ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-mn49n 1/1 Running 0 42m
myweb-k6fp0 1/1 Running 0 3m
myweb-m9nv9 1/1 Running 0 3m
(2)继续创建对应的Service
需要特别注意的是,在该Service文件中用到了type=NodePort和nodePort=30001这两个重要属性。
表明此Service开启了NodePort方式的外网访问模式。
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
selector:
app: myweb
[root@gqtest ~]# kubectl create -f myweb-svc.yaml
service "myweb" created
[root@gqtest ~]# kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.254.0.1 <none> 443/TCP 4h
mysql 10.254.20.191 <none> 3306/TCP 19m
myweb 10.254.89.4 <nodes> 8080:30001/TCP 1m
(3)测试下tomcat和mysql两个服务是否可以正确得互相连通并提供web服务
(4)查看一下此时系统中有哪些docker容器、哪些Pods
参考:《Kubernetes权威指南——从Docker到Kubernetes实践全接触》第1章。