petset翻译

时间:2024-01-09 19:41:50
Terminology
  通过这个文档,你将会看到一些术语,有时候他们在别的地方交叉使用,这可能会引起一些困惑。这一节的
是帮助你理清楚他们。
  • Node: 一个简单的虚拟或物理机在你的一个k8s集群中
  • Cluster: 一组在 single failure domain中的Node, 除非另有说明。
  • Persistent Volume Claim(PVC): 一个对存储的请求, 譬如一个持久存储
  • Host name: hostname附属于pod的UTS namespace,也就是pod输出的hotname
  • DNS/Domain name: 使用标准方法解析集群本地域名
  • Ordinality:  the proprety of being “ordinal”,  占据序列中的一个位置
  • Pet: 在一个Pet Set中的一个简单成员。更通俗的说法的是, 一个有状态的应用
  • Peer: 一个运行服务的进程,该进程有能力和其他进程通讯
What is a Pet Set
    在k8s中, 绝大部分的pod管理都是把pod抽象成微服务的一次性工作单元。 例如 Replication constrollers, 使用一个弱保证来设计的 - 对于特定的pod模板,应该有N个副本。pod会被作为无状态的单元对待, 如果其中一个pod不健康了或者需要被新版本替代了, 系统仅仅需要重新部署或者替换pod
    foo.default.svc.cluster.local
             |service|
             /       \
    | pod-asdf |    | pod-zxcv |
   一个Pet set, 通过对比,是一组有状态的pod,有状态的pod需要更健壮的身份概念。 在这篇文档中,把他认为是“成堆的应用( clustered applications)”
   *.foo.default.svc.cluster.local
    | mysql-0 | <-> | mysql-1 |
      [pv 0]          [pv 1]
集群应用的协调部署是出了名的难,他们需要更强壮的身份和资格概念,他们使用不透明度网络协议,而且还特别容易产生竞争条件和死锁
传统的管理员部署这些应用,是利用这些节点上稳定的,有这持久化存储和固定IP的长时间存活的实体。
Pet Set的目标是通过给一个有效的application实例指定个人身份来解耦这些依赖,不依赖底层物理基础设备( that are not anchored to the underlying physical infrastructure)。这个文档的剩余部分,我们会将这些实体定义为"Pets"  Our use of this term is predated by the “Pets vs Cattle” analogy
Pets和Pods的关系: PetSet要求这里有0到N-1个Pets, 每一个Pets有一个确定的名称- PetSet名称-序数, 它是一个唯一的名称。 每一个Pet最多有一个Pod, 每一个Pet Sets最多有一个给定身份的Pet
When to user Pet Set?
  一个Pet Set 确保任何指定时间内,有固定数目个带唯一身份标识的pets在运行。 一个Pet的身份是由以下三条因素定义的:
  1. 一个稳定的hostname, 在DNS中是有效的
  2. 一个序数索引
  3. 稳定的存储: 和hostanme和序数索引有关联的。
这些属性对部署有状态的应用都是有用的。 大部分有状态的应用都是成堆出现的,这就意味着他们通过依赖于存储状态的严格的资格要求进行结组。
 Pet Sets对这种应用在管理过程中遇到的两个特别普遍的问题是很有帮助的:
  1. discovery of peers for quorum
  2. startup/teardown ordering
当你的应用需要一些或者全部这样的特性的时候,使用Pet Sets就够了。 把pod作为无状态的副本管理是很简单的
Pet Sets的工作场景为:
  1. 像Mysql或者Postgresql这种一个实例在任何时候都需要一个持久化的存储卷的数据库
  2. 像Zookeeper,Etcd或者Elasticsearch这些需要稳定关系的集群应用
 Alpha limitations
   当你使用Pet Sets开始部署应用的时候,你需要明白,这里有一些局限性
  1. Pet Sets是一个 alpha resource, 在k8s 1.3之前的任何release版本都是不可以用的
  2. 在所有的alpha/beta中,都可以使用--runtime-config选项来传递给apiserver,从而禁用, 事实上,最有可能是在被托管的k8s上禁用
  3. 在Pet Sets中,唯一可更新的就是replicas
  4. 一个给定的Pet的存储,必须由基于要求的storage class的动态存储提供者提供(pv需要自己创建),或者由管理员预先提供。需要注意的是,动态提供存储卷的功能 也是在alpha中
  5. 删除Pet Set不能删除任何Pet, 你必须首先手动的将Pet Set配置中Pet规模缩放到0,或者删除Pet自己
  6. 删除Pet Set或将Pet Set配置中Pet数量缩小,并不会删除与Pet Set关联的存储卷。首先这是为了确保安全,毕竟你的数据比那些所有和Pet Set关联的可以被自动清洗的要有价值 ( your data is more valuable than an auto purge of all related Pet Set resources)
  7. 删除持久性存储卷的请求将会导致一个关联的存储卷删除
  8. 所有的Pet Set要求一个 "governing service",或者一个负责所有Pet的网络标识服务, 而用户负责此服务
  9. 更新一个已经存在的Pet Set就目前而言是一个手动的过程,这需要你重新使用新版本的镜像部署一个Pet Set 或者,把Pet一个一个孤立起来,更新他们的镜像,然后把它们添加回集群
Example Pet Set
  我们将会创建一个基础的Pet Set 来演示,Pets如何来指定一个唯一的、"sticky"的身份
# A headless service to create DNS records
# A headless service to create DNS records
apiVersion: v1
kind: Service
metadata:

  name: nginx
  labels:

    app: nginx
spec:

  ports:
  - port: 80
    name: web
  # *.nginx.default.svc.cluster.local
  clusterIP: None
  selector:

    app: nginx
---
apiVersion: apps/v1alpha1
kind: PetSet
metadata:
  name: web
spec:

  serviceName: "nginx"
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
      annotations:
        pod.alpha.kubernetes.io/initialized: "true"
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: nginx
        image: gcr.io/google_containers/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
      annotations:
        volume.alpha.kubernetes.io/storage-class: anything
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

  把这个配置文件保存为petset.yaml,然后把它提交给负责创建Pet Set和管理Pet的k8s的集群
$ kubectl create -f petset.yaml
service "nginx" created
petset "nginx" created
Pet Identity
 不论Pet是由哪一个node调度 ,pet的身份信息会一直跟随者他。我们可以查看刚刚创建的pet的身份信息
Ordinal Index
  你可以通过 $(petset name)-$(ordinal index assigned by petset controller)  这样的命令查看两个pod预先设置的名称
$ kubectl get po
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          10m
web-1     1/1       Running   0          10m
Stable storage
  两个pod,对应着两个持久存储卷。 这是Pet Set基于volumeTemplate字段自动创建的
$ kubectl get pv
NAME                                       CAPACITY   ACCESSMODES   STATUS    CLAIM               REASON    AGE
pvc-90234946-3717-11e6-a46e-42010af00002   1Gi        RWO           Bound     default/www-web-0             11m
pvc-902733c2-3717-11e6-a46e-42010af00002   1Gi        RWO           Bound     default/www-web-1             11m
Network identity
   网络标示由两部分组成。第一,我们创建一个headless Service来控制我们创建Pet Set时所在的域名。这个域名通过 $(service name).$(namespace).svc.cluster.local
 这样的方式来被Server管理,"cluster.local"是集群的域名
  每一个Pet被创建,都会得到一个匹配的DNS子域名,使用的方法为: $(petname).$(governing service domain),governing service是由Pet Set中的serviceName字段定义的。
  这里有一些选择Cluster Domain,Service name, Pet Set name, 如何影响Pets的DNS names,Pet中的pod的hostname的例子
Cluster Domain Service (ns/name) Pet Set (ns/name) Pet Set Domain Pet DNS Pet Hostname
cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1}
cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1}
kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..N-1}.nginx.foo.svc.kube.local web-{0..N-1}
需要注意的是, Cluster Domain将会被设置为cluster.local除非重写了配置信息
下面让我们用一个简单的测试来校验我们的断言
$ kubectl get svc
NAME          CLUSTER-IP     EXTERNAL-IP       PORT(S)   AGE
nginx         None           <none>            80/TCP    12m
...
首先PetSet提供了一一稳定的hostname
$ for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1
 
hostname是和集群中的DNS地址相关联的
$ kubectl run -i --tty --image busybox dns-test --restart=Never /bin/sh
dns-test # nslookup web-0.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.180.3.5

dns-test # nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.180.0.9

容器里运行了一个nginx web服务器, 他默认在会寻找 /usr/share/nginx/html/index.html文件
这个目录依靠Pet Set中的PersistentVolume字段来创建,现在,让我们在该文件中写下我们的hostname
$ for i in 0 1; do
  kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';
done
验证每一个web服务的服务器有它自己的hostname
$ for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1
现在删除Pet Set中所有的pod
$ kubectl delete po -l app=nginx
pod "web-0" deleted
pod "web-1" deleted
等执行完成后, try to retrieve the previously written hostname through the DNS name of the peer。 能匹配他们 ,是因为存储,DNS name, hostname一直跟随这Pet,不论Pet在哪里调度。
$ kubectl exec -it web-1 -- curl web-0.nginx
web-0
$ kubectl exec -it web-0 -- curl web-1.nginx
web-1
Peer discovery
  一个Pet可以把它自己的表示都组合到一块
  1. 使用 downward api发现他的pod name
  2. 使用 hostname 命令来发现DNS name
  3. 使用 mount或者df命令发现他的存储卷(通常,这不是必须的)
发现一个Pet Set的governing Service不是必须的,因为你可以通过一个有效的环境变量把它传递下去
通常pet需要找到他自己的peer,在前面的nginx例子中, 我们仅仅使用kubectl发现已存在的pod的名称,作为人,我们可以说明哪个pod属于指定的Pet Set,
另一个发现peer的方法是通过API Service,就像使用kubectl,但是这有一些缺点(你需要在你的应用容器中运行一个k8s指定的初始化系统,该系统的pid需要为1)
Pet Set为你提供了使用DNS记录发现peer的方法。为了阐述这个方法,我们是用先前的例子( note: one usually doesn’t apt-get in a container)
$ kubectl exec -it web-0 /bin/sh
web-0 # apt-get update && apt-get install -y dnsutils
...

web-0 # nslookup -type=srv nginx.default
Server:         10.0.0.10
Address:        10.0.0.10#53

nginx.default.svc.cluster.local service = 10 50 0 web-1.ub.default.svc.cluster.local.
nginx.default.svc.cluster.local service = 10 50 0 web-0.ub.default.svc.cluster.local.

Updating a Pet Set
 你可以不能更新PetSet的任何字段除了spec.replicas。 你可以通过使用标准的kubectl更新命令更新replicas字段,比如:path和edit。 Pet Set目前不支持更新image,这在limitations那一段已经作为标注指出来了。
Scaling a Pet Set
你可以通过更新"replicas"来对Pet Set进行缩放。需要注意的是,这个控制仅仅只能:
  1. 从0到N-1开始,在同一时间只能创建一个Pet,在创建下一个Pet之前,会等到前一个变成Runing and Ready
  2. 从N-1到0,同一时间只能删除一个,删除下一个之前需要等待前一个完全停止 (past its terminationGracePeriodSeconds)
$ kubectl get po
NAME     READY     STATUS    RESTARTS   AGE
web-0    1/1       Running   0          30s
web-1    1/1       Running   0          36s

$ kubectl patch petset web -p '{"spec":{"replicas":3}}'"web" patched

$ kubectl get po
NAME     READY     STATUS    RESTARTS   AGE
web-0    1/1       Running   0          40s
web-1    1/1       Running   0          46s
web-2    1/1       Running   0          8s

Deleting a Pet Set
  清除一个Pet Set 需要一点手工,就像在limiitations阶段标注的一样。 你可以使用Kubectl 删除一个Pet Set,但是它不会把Pet Set中的Pod缩减到0(貌似不能通过这种方式删除Pod)
$ kubectl delete -f petset.yaml
petset "web" deleted

$ kubectl get po -l app=nginx
NAME      READY     STATUS    RESTARTS   AGE
web-0     1/1       Running   0          21h
web-1     1/1       Running   0          21h

$ kubectl delete po -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

删除Pod也不会删除存储卷。 这需要管理员去删除这些存储卷。有一点可以肯定的是,你可以在删除存储卷之前有机会复制存储卷里的数据
Simply deleting the PVC after the pods have left the terminating state should trigger deletion of the backing Persistent Volumes
pod离开terminating state后,删除PVC,会引发备份持久化存储的删除
注意:一旦PVC删除,你将会失去你所有的数据, 请小心操作
$ kubectl get po -l app=nginx
$ kubectl get pvc -l app=nginx
NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-62d271cd-3822-11e6-b1b7-42010af00002   0                        21h
www-web-1   Bound     pvc-62d6750e-3822-11e6-b1b7-42010af00002   0                        21h

$ kubectl delete pvc -l app=nginx
$ kubectl get pv

如果你想清除上述所有,那么使用:
$ grace=$(kubectl get po web-0 --template '{{.spec.terminationGracePeriodSeconds}}')
$ kubectl delete petset,po -l app=nginx
$ sleep $grace
$ kubectl delete pvc -l app=nginx
Troubleshooting
  你可能注意到了在上面Pet Set的展示用都出现了annotations字段
annotations:
  pod.alpha.kubernetes.io/initialized: "true"
这个字段是一个调试钩子,它会暂停所有的Pet Set的缩小,扩大(规模的变化), 如果你想在每创建或删除一个pet的时候暂停petset,在模板中把他设置成false,等每一个pet创建之后,可以验证它是否被正确的初始化,然后在pet中使用kubectl edit把它设置成true, 在任一个pet中把它设置为false , 可以暂停Pet Set. 如果你不需要它,就像上面显示的一样,把它设置为true后再创建Pet Set. 这个在调试 debugging bootstrapping race conditions的时候是非常好用的