【K8S】K8S-网络模型、POD/RC/SVC YAML 语法官方文档

K8S-网络模型、POD/RC/SVC YAML 语法官方文档 

Kubernetes - Production-Grade Container Orchestration
kubernetes/kubernetes: Production-Grade Container Scheduling and Management
Posts containing 'yaml' - Stack Overflow
how to pass a configuration file thought yaml on kubernetes to create new replication controller - Stack Overflow
How to expose a Kubernetes service externally using NodePort - Stack Overflow
Yaml templates in Kubernetes - Stack Overflow
Kubernetes - Production-Grade Container Orchestration
kubernetes/examples at master · kubernetes/kubernetes
Kubernetes用户指南(二)--部署组合型的应用、链接应用到网络中 - 小黑 - 博客频道 - CSDN.NET
1、部署组合型的应用
 
一、使用配置文件启动replicas集合
 
k8s经过Replication Controller来建立和管理各个不一样的重复容器集合(其实是重复的pods)。
 
Replication Controller会确保pod的数量在运行的时候会一直保持在一个特殊的数字,即replicas的设置。
这个功能相似于Google GCE的实例组管理和AWS的弹性伸缩。
 
在快速开始中,经过kubectl run如下的YAML文件建立了一个rc运行着nginx:
 
apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
 
和定义一个pod的YAML文件相比,不一样的只是kind的值为ReplicationController,replicas的值须要制定,pod的相关定义在template中,pod的名字不须要显式地指定,由于它们会在rc中建立并赋予名字,点击查看完整的rc定义字段列表:
 
 
rc能够经过create命令像建立pod同样来建立:
 
$ kubectl create -f ./nginx-rc.yaml
replicationcontrollers/my-nginx
 
和直接建立pod不同,rc将会替换由于任何缘由而被删除或者中止运行的Pod,好比说pod依赖的节点挂了。因此咱们推荐使用rc来建立和管理复杂应用,即便你的应用只要使用到一个pod,在配置文件中忽略replicas字段的设置便可。
 
二、查看Replication Controller的状态
 
能够经过get命令来查看你建立的rc:
 
$ kubectl get rc
CONTROLLER   CONTAINER(S)   IMAGE(S)   SELECTOR    REPLICAS
my-nginx     nginx          nginx      app=nginx   2
 
这个状态表示,你建立的rc将会确保你一直有两个nginx的副本。
 
也能够和直接创pPod同样查看建立的Pod状态信息:
 
$ kubectl get pods
NAME             READY     STATUS    RESTARTS   AGE
my-nginx-065jq   1/1       Running   0          51s
my-nginx-buaiq   1/1       Running   0          51s
 
三、删除Replication Controller
 
当你想中止你的应用,删除你的rc,可使用:
 
$ kubectl delete rc my-nginx
replicationcontrollers/my-nginx
 
默认的,这将会删除全部被这个rc管理的pod,若是pod的数量很大,将会花一些时间来完成整个删除动做,若是你想使这些pod中止运行,请指定--cascade=false。
若是你在删除rc以前尝试删除pod,rc将会当即启动新的pod来替换被删除的pod,就像它承诺要作的同样。
 
四、Labels
 
k8s使用用户自定义的key-value键值对来区分和标识资源集合(就像rc、pod等资源),这种键值对称为label。
在上面的例子中,定义pod的template字段包含了一个简单定义的label,key的值为app,value的值为nginx。全部被建立的pod都会卸载这个label,能够经过-L参数来查看:
 
$ kubectl get rc my-nginx -L app
CONTROLLER   CONTAINER(S)   IMAGE(S)   SELECTOR    REPLICAS   APP
my-nginx     nginx          nginx      app=nginx   2          nginx
 
默认状况下,pod的label会复制到rc的label,一样地,k8s中的全部资源都支持携带label。
 
更重要的是,pod的label会被用来建立一个selector,用来匹配过滤携带这些label的pods。
你能够经过kubectl get请求这样一个字段来查看template的格式化输出:
 
$ kubectl get rc my-nginx -o template --template="{{.spec.selector}}"
map[app:nginx]
你也能够直接指定selector,好比你想在pod template中指明那些不想选中的label,可是你应该确保selector将会匹配这些从pod template中建立的pod的label,而且它将不会匹配其余rc建立的pod。
 
确保后者最简单的方法是为rc建立一个惟一的label值,而后在pod template的label和selector中都指定这个label。
 
 
2、链接应用到网络中
 
一、k8s中链接容器的模型
 
如今,你已经有了组合的、多份副本的应用,你能够将它链接到一个网络上。在讨论k8s联网的方式以前,有必要和Docker中链接网络的普通方式进行一下比较。
 
默认状况下,Docker使用主机私有网络,因此容器之间能够互相交互,只要它们在同一台机器上。
为了让Docker容器能够进行跨节点的交流,必须在主机的IP地址上为容器分配端口号,以后经过主机IP和端口将信息转发到容器中。
这样一来,很明显地,容器之间必须谨慎地使用和协调端口号的分配,或者动态分配端口号。
 
在众多开发者之间协调端口号的分配是十分困难的,会将集群级别以外的复杂问题暴露给用户来处理。
 
在k8s中,假设Pod之间能够互相交流,不管它们是在哪一个宿主机上。
咱们赋予每一个Pod本身的集群私有IP,如此一来你就不须要明确地在Pod之间建立链接,或者将容器的端口映射到主机的端口中。
这意味着,Pod中的容器能够在主机上使用任意彼此的端口,并且集群中的Pods能够在不使用NAT的方式下链接到其余Pod。
 
本章将会详细描述如何经过这样一个网络链接模型来运行稳定的Services。
 
本指南使用一个简单的nginx服务来验证以上的概念,在 Jenkins CI application有对相同概念的更加详细的说明。
 
二、在集群上将Pod链接到网络
 
咱们以前作过这个例子,可是让咱们以网络链接的角度来从新作一次。
建立一个nginx Pod,注意,这个Pod有一个容器端口的说明:
 
 
$ cat nginxrc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
 
这使它能够进入集群上的任意节点,检查节点上运行的Pod:
 
$ kubectl create -f ./nginxrc.yaml
$ kubectl get pods -l app=nginx -o wide
my-nginx-6isf4   1/1       Running   0          2h        e2e-test-beeps-minion-93ly
my-nginx-t26zt   1/1       Running   0          2h        e2e-test-beeps-minion-93ly
 
检查你的Pod的IPs:
 
$ kubectl get pods -l app=nginx -o json | grep podIP
                "podIP": "10.245.0.15",
                "podIP": "10.245.0.14",
 
这时,你应该可以经过ssh登陆任意节点而后使用curl来链接任一IP(若是节点之间没有处于同一个子网段,没法使用私有IP进行链接的话,就只能在对应节点上使用对应的IP进行链接测试)。
注意,容器并非真的在节点上使用80端口,也没有任何的NAT规则来路由流量到Pod中。
这意味着你能够在一样的节点上使用一样的containerPort来运行多个nginx Pod,而且能够在集群上的任何Pod或者节点经过这个IP来链接它们。
和Docker同样,端口仍然能够发布到宿主机的接口上,可是由于这个网络链接模型,这个需求就变得不多了。
 
若是你好奇的话,能够经过这里查看咱们是如何作到的:
 
三、建立Service
 
如今,在集群上咱们有了一个运行着niginx而且有分配IP地址空间的的Pod。
理论上,你能够直接和这些Pod进行交互,可是当节点挂掉以后会发生什么?
这些Pod会跟着节点挂掉,而后RC会在另一个健康的节点上从新建立新的Pod来代替,而这些Pod分配的IP地址都会发生变化,对于Service类型的服务来讲这是一个难题。
 
k8s上的Service是抽象的,其定义了一组运行在集群之上的Pod的逻辑集合,这些Pod是重复的,复制出来的,因此提供相同的功能。
当Service被建立,会被分配一个惟一的IP地址(也称为集群IP)。这个地址和Service的生命周期相关联,而且当Service是运行的时候,这个IP不会发生改变。
Pods进行配置来和这个Service进行交互,以后Service将会自动作负载均衡到Service中的Pod。
 
你能够经过如下的YAML文件来为你的两个nginx容器副本建立一个Service:
 
$ cat nginxsvc.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginxsvc
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    app: nginx
 
这个YAML定义建立建立一个Service,带有Label为app=nginx的Pod都将会开放80端口,并将其关联到一个抽象的Service端口。
(targetPort字段是指容器内开放的端口Service经过这个端口链接Pod,port字段是指抽象Service的端口,nodePort为节点上暴露的端口号,不指定的话为随机。)
点击这里查看完整的Service字段列表:
 
 
如今查看你建立的Service:
 
$ kubectl get svc
NAME         CLUSTER_IP       EXTERNAL_IP       PORT(S)                SELECTOR     AGE
kubernetes   10.179.240.1     <none>            443/TCP                <none>       8d
nginxsvc     10.179.252.126   122.222.183.144   80/TCP,81/TCP,82/TCP   run=nginx2   11m
 
和以前提到的同样,Service是以一组Pod为基础的。
这些Pod经过endpoints字段开放出来。
Service的selector将会不断地进行Pod的Label匹配,结果将会通知一个Endpoints Object,这里建立的也叫作nginxsvc。
当Pod挂掉以后,将会自动从Endpoints中移除,当有新的Pod被Service的selector匹配到以后将会自动加入这个Endpoints。
你能够查看这个Endpoint,注意,这些IP和第一步中建立Pods的时候是同样的:
 
$ kubectl describe svc nginxsvc
Name:           nginxsvc
Namespace:      default
Labels:         app=nginx
Selector:       app=nginx
Type:           ClusterIP
IP:         10.0.116.146
Port:           <unnamed>   80/TCP
Endpoints:      10.245.0.14:80,10.245.0.15:80
Session Affinity:   None
No events.
$ kubectl get ep
NAME         ENDPOINTS
nginxsvc     10.245.0.14:80,10.245.0.15:80
 
你如今应该能够经过10.0.116.146:80这个IP从集群上的任何一个节点使用curl命令来链接到nginx的Service。
注意,Service的IP是彻底虚拟的,若是你想知道它是怎么工做的,请点击:
 
四、Pod发现并加入到Service中
 
k8s提供了两种基本的方式来发现Service:环境变量和DNS。
环境变量是当即可使用的,DNS则须要kube-dns集群插件。
 
五、环境变量
 
当Pod运行在一个节点上,kubelet将会为每一个激活的Service添加一系列的环境变量。
为你的nginx Pod检查一下环境:
$ kubectl exec my-nginx-6isf4 -- printenv | grep SERVICE
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_SERVICE_PORT=443
 
注意,这里没有显示和Service相关的东西,由于这个Pod是在Service以前建立的,这种作法另一个缺点是,
Scheduler可能会将两个Pod都在同一个机器上启动,这样一来,当节点挂掉以后整个Service也会挂掉。     
这里正确的作法是杀死两个Pod,等待RC从新启动新的Pod来代替。
这样一来,Service就在那些副本以前存在,并将环境变量设置到全部的Pod中。
正确的环境变量应为:
 
$ kubectl scale rc my-nginx --replicas=0; kubectl scale rc my-nginx --replicas=2;
$ kubectl get pods -l app=nginx -o wide
NAME             READY   STATUS     RESTARTS   AGE   NODE
my-nginx-5j8ok   1/1     Running    0         2m    node1
my-nginx-90vaf   1/1     Running   0          2m    node2

$ kubectl exec my-nginx-5j8ok -- printenv | grep SERVICE
KUBERNETES_SERVICE_PORT=443
NGINXSVC_SERVICE_HOST=10.0.116.146
KUBERNETES_SERVICE_HOST=10.0.0.1
NGINXSVC_SERVICE_PORT=80
 
六、DNS
 
k8s提供了一个DNS集群服务插件,使用skydns来自动分配DNS给其余的Service。若是你的集群上有运行的话,你能够查看它的状态:
 
$ kubectl get services kube-dns --namespace=kube-system
NAME       CLUSTER_IP      EXTERNAL_IP   PORT(S)         SELECTOR           AGE
kube-dns   10.179.240.10   <none>        53/UDP,53/TCP   k8s-app=kube-dns   8d
若是集群上没有运行,那么你能够启用它: enable it
 
本节剩下的内容是在假设你拥有一个长时间可使用IP的Service(nginxsvc)而且DNS域名已经经过dns服务(DNS集群服务插件)分配给这个IP的前提下。
因此你能够在集群上的任一节点中使用标准的请求方法来链接Service,如今来建立另一个Pod进行测试:
 
$ cat curlpod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: curlpod
spec:
  containers:
  - image: radial/busyboxplus:curl
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
    name: curlcontainer
  restartPolicy: Always
执行查找nginx Service:
 
$ kubectl create -f ./curlpod.yaml
default/curlpod
$ kubectl get pods curlpod
NAME      READY     STATUS    RESTARTS   AGE
curlpod   1/1       Running   0          18s

$ kubectl exec curlpod -- nslookup nginxsvc
Server:    10.0.0.10
Address 1: 10.0.0.10
Name:      nginxsvc
Address 1: 10.0.116.146
七、使用加密链接的Service
 
到目前为止,咱们仅仅是在集群中链接了nginx服务,在将服务开放到Internet上以前,你须要确认双方交流的通道是安全的。
你将会须要如下的东西来确保安全性:
 
  • HTTPS自签名证书(或者你已经有了一个证书)
  • 一个nginx服务配置好了使用这个证书
  • 一个加密措施使得证书在Pod之间交流使用
 
你能够经过这里
来得到完整的配置方式,简要地说,方式以下:
 
$ make keys secret KEY=/tmp/nginx.key CERT=/tmp/nginx.crt SECRET=/tmp/secret.json
$ kubectl create -f /tmp/secret.json
secrets/nginxsecret
$ kubectl get secrets
NAME                  TYPE                                  DATA
default-token-il9rc    kubernetes.io/service-account-token   1
nginxsecret           Opaque                                2
 
如今修改你的nginx副原本启动一个使用这个证书的HTTPS服务和Service,而且都开放80和443端口:
 
$ cat nginx-app.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginxsvc
  labels:
    app: nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    protocol: TCP
    name: https
  selector:
    app: nginx
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: my-nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: nginxhttps
        image: bprashanth/nginxhttps:1.0
        ports:
        - containerPort: 443
        - containerPort: 80
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
 
nginx-app中值得注意的点有:
 
  • 其包括了RC和SVC的定义在同一个文件中
  • nginx服务的HTTP经过80端口,HTTPS经过443端口
  • 每一个容器都经过挂载在/etc/nginx/ssl卷中的keys来链接。这步是在nginx服务启动以前完成的
 
$ kubectl delete rc,svc -l app=nginx; kubectl create -f ./nginx-app.yaml
replicationcontrollers/my-nginx
services/nginxsvc
services/nginxsvc
replicationcontrollers/my-nginx
此时,你能够在任意节点上访问nginx服务
 
$ kubectl get pods -o json | grep -i podip
    "podIP": "10.1.0.80",
node $ curl -k  https://10.1.0.80
...
<h1>Welcome to nginx!</h1>
 
注意在最后一步中,咱们是如何使用-k这个参数的,由于咱们不知道任何有关nginx服务运行的Pod的证书生成时刻,因此咱们要告诉curl忽略别名不匹配。
经过建立一个Service,在Pod发现Service的时候咱们将证书中使用的别名和真实地DNS域名关联起来,让咱们经过一个Pod来测试(这里会重用这个证书,Pod链接Service只须要nginx.crt):
 
$ cat curlpod.yaml
vapiVersion: v1
kind: ReplicationController
metadata:
  name: curlrc
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: curlpod
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: curlpod
        command:
        - sh
        - -c
        - while true; do sleep 1; done
        image: radial/busyboxplus:curl
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume

$ kubectl create -f ./curlpod.yaml
$ kubectl get pods
NAME             READY     STATUS    RESTARTS   AGE
curlpod          1/1       Running   0          2m
my-nginx-7006w   1/1       Running   0          24m

$ kubectl exec curlpod -- curl  https://nginxsvc --cacert /etc/nginx/ssl/nginx.crt
...
<title>Welcome to nginx!</title>
...
 
八、开放Service
 
在你的应用中可能须要将其开放到一个外部的IP中。
k8s提供了两种方式:NodePorts和LoadBalancers。
在上面的最后一部分中,咱们已经经过NodePorts方式建立了Service,因此若是你有公网IP,你的nginx https副本就能够在Internet上开放了。
 
$ kubectl get svc nginxsvc -o json | grep -i nodeport -C 5
            {
                "name": "http",
                "protocol": "TCP",
                "port": 80,
                "targetPort": 80,
                "nodePort": 32188
            },
            {
                "name": "https",
                "protocol": "TCP",
                "port": 443,
                "targetPort": 443,
                "nodePort": 30645
            }
 
$ kubectl get nodes -o json | grep ExternalIP -C 2
                    {
                        "type": "ExternalIP",
                        "address": "104.197.63.17"
                    }
--
                    },
                    {
                        "type": "ExternalIP",
                        "address": "104.154.89.170"
                    }
$ curl  https://104.197.63.17:30645 -k
...
<h1>Welcome to nginx!</h1>
 
如今,咱们将经过负载均衡器从新建立一个Service,只须要将nginx-app.yaml文件中的type字段从NodePort改成LoadBalancer便可:
 
$ kubectl delete rc, svc -l app=nginx
$ kubectl create -f ./nginx-app.yaml
$ kubectl get svc nginxsvc
NAME      CLUSTER_IP       EXTERNAL_IP       PORT(S)                SELECTOR     AGE
nginxsvc  10.179.252.126   162.222.184.144   80/TCP,81/TCP,82/TCP   run=nginx2   13m

$ curl  https://162.22.184.144 -k
...
<title>Welcome to nginx!</title>
 
EXTERNAL_IP这列的IP便是能够在公网上访问的IP,CLUSTER_IP只能在本身的集群上访问到。
相关文章
相关标签/搜索