前言:
之前我们画过下面这张图,通过图我们可以看出ReplicaSet是维护Pod,而Deployment是维护ReplicaSet的。那么我们就从Pod入手,毕竟Pod是Kubernetes的基础,没有Pod其他的都没任何用。
Pod是Kubernetes的基础,我们如何动态扩展Pod的数量以及动态下线某Pod呢?通过官网我们可以看到,ReplicatSet、ReplicationController、Deployment都可以维护Pod的数量。下面我们详细从Pod开始详细介绍一下Kubernetes的核心。
一、ReplicationController
官网:https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/
通过官网我们可以看出ReplicationController能保证任何时间点都有固定数量的pod副本在运行,总而言之就是ReplicationController可以保证一个或者一组Pod一直处于可用状态。
上面的话可以换成:ReplicationController可以保证一定数量的Pod一直处于运行状态,一旦Pod副本数量小于设置的数量,就会立即创建Pod以达到设置的数量(减少了传统IT环境手工运维的工作),而且还能筛选出同一组Pod,通过官网我们可以看出是通过Label Selector来筛选的。
之前生成Pod的时候我们写过yml文件,现在我们也可以写一个yml文件来生成对应的Pod,当然这个yml文件不是我自己写的,官网都有例子,自己拿下来改吧改吧就行了。
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
kind:表示要创建对象的类型;
spec.repicas:ReplicationController要管理的Pod的副本数;
spec.selectot:ReplicationController要管理的Pod的label,之前讲过label是key:value形式的;
spec.template:定义Pod的模板,当有Pod挂了数量达不到repicas的数量时会根据spec.template生成新的Pod,例如Pod名称、label以及Pod中运行的应用等;通过改变模板中镜像的版本,可以实现Pod的升级功能(滚动更新rolling-update);
通过运行kubectl apply -f xxx.yml命令可以创建3个Pod,并且每个Pod都有相同的label(app:nginx),同时每个Pod都会运行一个nginx容器。如果某个Pod发生了问题,ReplicationController能够及时发现并创建新的Pod。
相应的命令:
创建Pod:kubectl apply -f xxx.yml
查看Pod:kubectl get pods -o wide
kubectl get rc
尝试删除一个pod:kubectl delete pods podName
查看所有的pod:kubectl get pods
删除所有的pod:kubectl delete -f xxx.yml
也可以动态对pod扩缩容:kubectl scale rc podName--replicas=5
**注意:**可以看到官网建议在Deployment中用ReplicatSet来代替ReplicationController完成复制功能,下面就介绍一下ReplicatSet。
ReplicationController也简称为RC,ReplicatSet简称为RS。
二、ReplicaSet
官网:https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
ReplicaSet也是对Pod进行管理。通过官网我们可以看到在Kubernetes v1.2时,ReplicationController升级为另一个概念ReplicaSet,也就是说ReplicaSet是ReplicationController的升级版,官方解释就是下一代RC。
RS和RC没有本质的区别,kubectl中绝大多数作用于RC的命令同样能适用于RS.
RS和RC唯一的区别:RS支持基于集合的Label Selector,而RC只支持基于等式的Label Selector,这使得RS的功能更强。
我们来看一下RS创建Pod的yml文件:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key:tier,operator: In,values: [frontend]}
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
通过上面可以看出,唯一不同的就是label selector的表达式不同
**注意:**一般情况下,我们很少单独使用RS,它主要是被Deployment这个更高的资源对象所使用,从而形成一整套Pod创建、删除、更新的编排机制。当我们使用Deloyment时,无须关心它是如何创建和维护RS的,这一切都是自动发生的,同时,也无须担心跟其他机制的不兼容问题(比如ReplicaSet不支持rolling-update(容器镜像动态升级)但Deployment支持,ReplicationController也支持)。
三、Deployment
官网:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
我们可以看到Deployments不仅可以声明和更新ReplicaSet也能声明和更新Pods。
Deployment相对于RC来讲最大的一个升级就是我们可以随时知道当前Pod部署的进度。
我们一般利用yml文件创建一个Deployment对象来生成对应的RS并完成Pod副本的创建。检查Deployment状态来看部署动作是否完成,也就是Pod副本数量是否达到设置的数量。
我们来看一下创建Deployment的yml文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
该yml文件看起来跟RC的特别的相似,就个别地方不一样。
我们可以使用一下命令来查看对应的pod和deployment的创建情况:
kubectl apply -f xxx.yml
查看pod:kubectl get pods -o wide
kubectl get deployment
kubectl get rs
kubectl get deployment -o wide
直接更新imges版本:kubectl set image deployment deploymentName nginx=nginx:1.9.1
注意: ReplicationController、ReplicaSet、Deployment都是Controller。
四、Label and Selectors
官网:https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
通过上面的介绍就能看出来,lable就是给Pod打标签,key:value的形式,我们可以将具有相同label的Pod交给Select管理。
查看pod的label标签:kubectl get pods --show-labels
五、Namespace
命名空间就是为了隔离不同的资源,比如Pod,Service,Deployment等。可以在输入命令的时候指定命名空间-n +空间名,如果不指定就会用默认的命名空间:default。
也可以用yml文件创建命名空间,文件格式如下:
apiVersion: v1
kind: Namespace
metadata:
name: myns
当然还是使用kubectl apply -f xxx.yml来创建
其他的命令:
查看所有的namespace:kubectl get namespaces/ns
查看某命名空间下的pod:kubectl get pods -n namespaceName
查看某命名空间下的所有资源:kubectl get all -n namespaceName
查看所有命名空间下的pd:kubectl get pods --all-namespaces
查看默认空间下的pod:kubectl get pods
在某命名空间下创建pod,主需要在yml文件中的metadata中加入namespace即可:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: namespaceName
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80
六、NetWork
(一)同一个Pod中的容器通信
通过官网的话我们可以看出,同一个Pod内的容器是共享网络ip和端口的,所以通信显然没问题。
如果不通过ip和端口而想通过容器名进行访问呢?就需要将所有pod中的容器加入到同一个容器的网络中,我们把该容器成为为pod的pause container。
(二)集群内Pod之间的通信
每个Pod都有自己独立的IP地址,这个IP地址能被Pod内的Container共享,那么集群内的Pod能通过这个独立的IP进行通信吗?
集群内Pod之间的通信可以分为两种情况,一个是Pod在同一台机器,另一个是Pod在不同的机器,通过实验可以发现这两种情况是都能通信的,这里就不放代码了,有兴趣的小伙伴可以私聊我,我单独发。
虽然是能通信,但是是什么来支持他们之间的通信呢?其实通过官网我们就能知道,是插件帮我们做的,帮我们做这个的插件很多,我们主要用的就是Calico,后面会针对这个详细介绍。
官网:https://kubernetes.io/docs/concepts/cluster-administration/networking/#the-kubernetes-network-model
(三)集群内Service-Cluster IP
虽然集群中的Pod能够相互通信,但是Pod是不稳定的,因为我们通过Deployment管理Pod时会对Pod进行扩缩容,这时Pod的地址是发生变化的,通过ip访问就不可靠了。这时Service的作用就出来了,我们给同一类Pod打上标签,组成Service,Service有固定的ip,它会自动跟其管理的Pod进行负载均衡,这样无论Pod怎么创建和销毁我们通可以通过Sercice的IP进行访问。
官网:https://kubernetes.io/docs/concepts/services-networking/service/
1、用yml直接创建pod,yml中类型还是Deployment;
2、创建service:
kubectl expose deployment whoami-deployment
3、然后运行:kubectl get svc
就会出现类型为Cluster IP的service,然后通过访问发现能访问,但是Cluster IP类型的网络只能集群内通信。
其他命令:
删除svc kubectl delete service whoami-deployment
(四)Pod访问外部应用
直接访问就是了
(五)外部应用访问集群内的Pod
1、NodePort
也是Service的一种,简单来说就是外部应用能访问集群的物理主机IP,所以就是在集群中每台物理机器上暴露一个IP。
1、先创建pod,yml文件直接参考Deployment那个模块的就行;
2、然后创建NodePort类型的Service,名称最好和deployment保持一致。
kubectl delete svc serviceName
kubectl expose deployment serviceName --type=NodePort
3、再运行kubectl get svc
上图中的32041就是物理主机对外暴露的端口,通过浏览器访问发现能访问。但是这样不好之处就是会占用物理主机的端口。
Service除了NodePort方式以外还有一种方式是LoadBalance,但是这种需要第三方云提供商支持具有约束性。下面就介绍一种更好的方法,Ingress网络。
2、Ingress
官网:https://kubernetes.io/docs/concepts/services-networking/ingress/
通过官网的介绍,我们可以看到Ingress能够帮助我们访问集群内的服务,而且还提供了负载均衡、本地终结SSL会话以及基于名称的虚拟主机等功能。
上面讲了通过Service的NodePort方式来让外部应用访问集群内的Pod,但是这种方案在生产中不推荐,因此就可以用Ingress网络,在外部应用和Service之间使用,外部访问Ingress网络,然后通过Ingress再访问Service,然后Service再映射到对应的Pod。是不是有种Nginx负载均衡转发的感觉。
Ingress网络需要Ingress Controller,这是官网的介绍,我理解的就是Ingress是一个概念,而Ingress Controller就是针对这个概念具体的应用。
外部访问集群内的服务,一般我们都会使用Nginx做负载均衡,而现在我们使用Ingress来做了负载均衡。其实有开源爱好者把Nginx和Ingress结合起来了,也就是Nginx Ingress Controller,可以参考对应的官网:https://kubernetes.github.io/ingress-nginx/。github地址:https://github.com/kubernetes/ingress-nginx;kubernete官网关于Ingress的说明:https://kubernetes.io/docs/concepts/services-networking/ingress/。
就像我们不用kubernetes时一样,我们安装Nginx然后在nginx.conf下配置对应的访问规则,而用了kubernetes以后我们总不能还是安装Nginx然后在nginx.conf继续配置吧,用了kubernetes我们就要整套都智能化。我们只需要 创建Nginx Ingress Controller以及对应的Ingress规则,而且这是一次性的,安装以后不用再安装,只需要改一下Ingress规则即可。
这里讲一下外界通过Ingress Nginx Controller访问tomcat的Pod具体步骤:
2.1、创建Ingress Nginx Controller
通过NGINX Ingress Controller的官网,我们能找到创建NGINX Ingress Controller的yml文件,由于yml文件的内容太多了,我这里就不复制出来了,大家可以根据地址自行下载:
或者直接github下载:https://github.com/kubernetes/ingress-nginx/blob/master/deploy/static/provider/baremetal/deploy.yaml
用以下命令创建Ingress Nginx Controller:
kubectl apply -f xxx.yml
查看:kubectl get all -n ingress-nginx
注意: 镜像拉取需要较长的时间,这块注意一下哦
2.2、以HostPort的方式创建
以Deployment方式创建Ingress Nginx Controller的Pod,要想让外界访问可以通过Service的NodePort或者HostPord方式,这两种方式Nginx Ingress Controller的官网都有介绍(上图红色圈出来的地方: Bare-metal considerations就是介绍Service的NodePort、HostPord以及其他方式的入口)。官网推荐使用NodePort的方式,但是我们上面说了但是我们上面说了NodePort会占用物理机的端口,会在所有有Service的物理主机都对外暴露一个单独的端口。所以我这里选择了HostPort的方式,在Ingress Controller对应的物理机器上对外暴露一个port即可,由于Ingress Controller创建以后在哪台机器上不固定,所以我们可以指定在固定节点运行Ingress Nginx Controller的Pod;
2.2.1、使用HostPort方式运行
需要增加配置,在Ingress Nginx Controller对应的yml文件中加入hostNetWork:true:
2.2.2、给节点打上标签
kubectl label node w1 name=ingress
给节点w1打上name=ingress的标签,这里的w1是节点的别名;
然后在Ingress Nginx Controller对应的yml文件中加入nodeSelector:
2.2.3、检查端口占用
通过Ingress Nginx Controller对应的yml文件我们可以看到,Ingress Controller是通过80和443对外暴露的,所以要确保w1节点上的80和443端口没有被占用
查看w1的80和443端口有没有被占用:
lsof -i tcp:80
lsof -i tcp:443
2.3、创建tomcat的pod和service
tomcat的pod对应的yml文件(容器对外暴露的是8080端口):
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
labels:
app: tomcat
spec:
replicas: 1
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcat
image: tomcat
ports:
- containerPort: 8080
可以使用以下命令:
创建tomcat的pod:kubectl apply -f tomcat.yml
查看创建的pod:kubectl get pods
tomcat的service对应的yml文件(service对外暴露的是80端口,指向pod的8080端口):
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: tomcat
可以使用以下命令:
创建tomcat的service:kubectl apply -f tomcat-service.yml
查看创建的service:kubectl get svc
2.4、创建Ingress以及定义转发规则
当然也是用yml的方式,官网有对应的yml文件还有对应的配置规则详细说明,我这里只是配置了最简单的,只要访问我的域名,我就映射到到tomcat-service的服务的80端口
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress
spec:
rules:
- host: tomcat.jack.com
http:
paths:
- path: /
backend:
serviceName: tomcat-service
servicePort: 80
可以使用如下的命令:
创建ingress:kubectl apply -f nginx-ingress.yaml
查看创建的ingress: kubectl get ingress
查看详情排查问题:kubectl describe ingress nginx-ingress
2.5、访问
打开浏览器访问tomcat.jack.com,前提是你这个域名有公网地址这样才能解析出来,或者你自己在本地配置了dns解析,修改本地的host文件即可。
2.6、总结
如果以后想使用Ingress网络,其实只要定义ingress规则,service和pod即可,前提是保证nginx ingress controller已经配置好了。