前言:

之前我们画过下面这张图,通过图我们可以看出ReplicaSet是维护Pod,而Deployment是维护ReplicaSet的。那么我们就从Pod入手,毕竟Pod是Kubernetes的基础,没有Pod其他的都没任何用。

kubernetes查看pod yaml kubernetes查看容器核心数_Kubernetes


Pod是Kubernetes的基础,我们如何动态扩展Pod的数量以及动态下线某Pod呢?通过官网我们可以看到,ReplicatSet、ReplicationController、Deployment都可以维护Pod的数量。下面我们详细从Pod开始详细介绍一下Kubernetes的核心。

一、ReplicationController

官网:https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/

kubernetes查看pod yaml kubernetes查看容器核心数_k8s核心组件_02


通过官网我们可以看出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/

kubernetes查看pod yaml kubernetes查看容器核心数_k8s核心组件_03


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/

kubernetes查看pod yaml kubernetes查看容器核心数_Kubernetes_04


我们可以看到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/

kubernetes查看pod yaml kubernetes查看容器核心数_kubernetes核心_05


通过上面的介绍就能看出来,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中的容器通信

kubernetes查看pod yaml kubernetes查看容器核心数_kubernetes核心_06

通过官网的话我们可以看出,同一个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

kubernetes查看pod yaml kubernetes查看容器核心数_nginx_07

(三)集群内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/

kubernetes查看pod yaml kubernetes查看容器核心数_Kubernetes_08

1、用yml直接创建pod,yml中类型还是Deployment;
2、创建service:

kubectl expose deployment whoami-deployment

3、然后运行:kubectl get svc就会出现类型为Cluster IP的service,然后通过访问发现能访问,但是Cluster IP类型的网络只能集群内通信。

kubernetes查看pod yaml kubernetes查看容器核心数_k8s核心组件_09


其他命令:

删除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

kubernetes查看pod yaml kubernetes查看容器核心数_kubernetes核心_10


上图中的32041就是物理主机对外暴露的端口,通过浏览器访问发现能访问。但是这样不好之处就是会占用物理主机的端口。

Service除了NodePort方式以外还有一种方式是LoadBalance,但是这种需要第三方云提供商支持具有约束性。下面就介绍一种更好的方法,Ingress网络。

2、Ingress

官网:https://kubernetes.io/docs/concepts/services-networking/ingress/

kubernetes查看pod yaml kubernetes查看容器核心数_k8s核心组件_11


通过官网的介绍,我们可以看到Ingress能够帮助我们访问集群内的服务,而且还提供了负载均衡、本地终结SSL会话以及基于名称的虚拟主机等功能。

kubernetes查看pod yaml kubernetes查看容器核心数_nginx_12


上面讲了通过Service的NodePort方式来让外部应用访问集群内的Pod,但是这种方案在生产中不推荐,因此就可以用Ingress网络,在外部应用和Service之间使用,外部访问Ingress网络,然后通过Ingress再访问Service,然后Service再映射到对应的Pod。是不是有种Nginx负载均衡转发的感觉。

kubernetes查看pod yaml kubernetes查看容器核心数_nginx_13


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规则即可。

kubernetes查看pod yaml kubernetes查看容器核心数_Kubernetes_14


这里讲一下外界通过Ingress Nginx Controller访问tomcat的Pod具体步骤:

2.1、创建Ingress Nginx Controller

通过NGINX Ingress Controller的官网,我们能找到创建NGINX Ingress Controller的yml文件,由于yml文件的内容太多了,我这里就不复制出来了,大家可以根据地址自行下载:

kubernetes查看pod yaml kubernetes查看容器核心数_kubernetes核心_15


或者直接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:

kubernetes查看pod yaml kubernetes查看容器核心数_kubernetes核心_16

2.2.2、给节点打上标签

kubectl label node w1 name=ingress
给节点w1打上name=ingress的标签,这里的w1是节点的别名;

然后在Ingress Nginx Controller对应的yml文件中加入nodeSelector:

kubernetes查看pod yaml kubernetes查看容器核心数_k8s核心组件_17

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已经配置好了。