在第一篇博文中,讲到Puppet和Kubernetes,介绍了新的关于Kubernetes的Puppet模块并且讲述了关于配置管理和现代分布式集群系统。在这篇文章中,我们通过具体的例子来深入更多细节。
Kubernetes的Hello World示例是一个“Guestbook”应用。它通过使用Kubernetes的RC和services来创建了一个redis的主从配置和web应用的一个负载均衡器。所以,还有什么例子能比这更好的展示新的Kubernetes的Puppet模块呢?
如果你想自己尝试一下,你需要一个可以工作的Kubernetes集群。官方文档写了很多自己搭建的方法;最简单的方法是使用Google的GCE服务。
设置Kubernetes模块使用kubeclient库调用Kubernetes API。需要先安装这个库,但会根据安装Puppet的方式而有所不同,对于最新版的puppet-agent,你需要运行:
/opt/puppetlabs/puppet/bin/gem install kubeclient --no-ri --no-rdoc之后通过下面方法来安装模块本身:
puppet module install garethr-kubernetes最后需要给Puppet提供一个可运行的kubectl配置文件。假定我们使用如下配置来运行Kubernetes:
cp ~/.kube/config ~/.puppetlabs/etc/puppet/kubernetes.conf接下来我们可以配置Puppet。
在Puppet中描述Kubernetes资源接下来,演示官方guestbook的例子,使用特定的YAML文件和kubectl命令来创建资源。配置如下:
apiVersion: v1 kind: Service metadata: name: redis-master labels: app: redis role: master tier: backend spec: ports: - port: 6379 targetPort: 6379 selector: app: redis role: master tier: backend在下面的例子中,你会看到等价的Puppet的配置。首先,明显看到Puppet配置使用同样的结构。它提供了一个低层的接口,对于熟悉Kubernetes的人可以很快识别出。Puppet已经提供了很多方式在这些原始的接口上来构建新的抽象层。
首先创建redis master的 RC。会按流程创建单个Pod来运行redis。
kubernetes_replication_controller { 'redis-master': ensure => 'present', metadata => { 'labels' => {'app' => 'redis', 'role' => 'master', 'tier' => 'backend'}, 'namespace' => 'default', }, spec => { 'replicas' => 1, 'template' => { 'metadata' => { 'labels' => {'app' => 'redis', 'role' => 'master', 'tier' => 'backend'}, }, 'spec' => { 'containers' => [ { 'image' => 'redis', 'name' => 'master', 'ports' => [ {'containerPort' => 6379, 'protocol' => 'TCP'} ], 'resources' => { 'requests' => { 'cpu' => '100m', 'memory' => '100Mi', } } } ] } } } }我们同样可以使用如下配置文件,来运行创建对应的redis master service。
kubernetes_service { 'redis-master': ensure => 'present', metadata => { 'labels' => {'app' => 'redis', 'role' => 'master', 'tier' => 'backend'}, 'namespace' => 'default', }, spec => { 'ports' => [ {'port' => 6379, 'protocol' => 'TCP', 'targetPort' => 6379} ], 'selector' => { 'app' => 'redis', 'role' => 'master', 'tier' => 'backend', } } }接下来启动redis slave的RC配置,运行两个备份。同样以类似YAML格式的配置来匹配。
kubernetes_replication_controller { 'redis-slave': ensure => 'present', metadata => { 'labels' => {'app' => 'redis', 'role' => 'slave', 'tier' => 'backend'}, 'namespace' => 'default', }, spec => { 'replicas' => '2', 'template' => { 'metadata' => { 'labels' => {'app' => 'redis', 'role' => 'slave', 'tier' => 'backend'} }, 'spec' => { 'containers' => [ { 'env' => [{'name' => 'GET_HOSTS_FROM', 'value' => 'dns'}], 'image' => 'gcr.io/google_samples/gb-redisslave:v1', 'name' => 'slave', 'ports' => [ {'containerPort' => '6379', 'protocol' => 'TCP'} ], 'resources' => {'requests' => {'cpu' => '100m', 'memory' => '100Mi'}}, } ] } } } }同时创建与生成的Pods对应的Service。
kubernetes_service { 'redis-slave': ensure => 'present', metadata => { 'labels' => {'app' => 'redis', 'role' => 'slave', 'tier' => 'backend'}, 'namespace' => 'default', }, spec => { 'ports' => [ {'port' => 6379, 'protocol' => 'TCP'} ], 'selector' => { 'app' => 'redis', 'role' => 'slave', 'tier' => 'backend', } } }接下来是前端的负载均衡控制器,为web应用提供服务的RC数为3个。
kubernetes_replication_controller { 'frontend': ensure => 'present', metadata => { 'labels' => {'app' => 'guestbook', 'tier' => 'frontend'}, 'namespace' => 'default', }, spec => { 'replicas' => '3', 'template' => { 'metadata' => { 'labels' => {'app' => 'guestbook', 'tier' => 'frontend'} }, 'spec' => { 'containers' => [ { 'env' => [{'name' => 'GET_HOSTS_FROM', 'value' => 'dns'}], 'image' => 'gcr.io/google_samples/gb-frontend:v3', 'name' => 'php-redis', 'ports' => [ {'containerPort' => '80', 'protocol' => 'TCP'} ], 'resources' => {'requests' => {'cpu' => '100m', 'memory' => '100Mi'}}, } ] } } } }最后为前端的web应用Pod创建一个负载均衡service。
运行实例以上截取的片段是官方指南中的六个步骤。通过Puppet,我们使用一条命令和一个配置文件就可以创建出所有这些资源。以上所有源代码都可以在示例目录模块找到(https://github.com/garethr/garethr-kubernetes/blob/master/examples/guestbook.pp)。
通过Puppet本地测试用例如下所示:
$ puppet apply examples/guestbook.pp --test Info: Loading facts Info: Loading facts Notice: Compiled catalog for pro.local in environment production in 0.33 seconds Info: Applying configuration version '1448445589' Info: Checking if frontend exists Info: Creating kubernetes_service frontend Notice: /Stage[main]/Main/Kubernetes_service[frontend]/ensure: created Info: Checking if frontend exists Info: Creating kubernetes_replication_controller frontend Notice: /Stage[main]/Main/Kubernetes_replication_controller[frontend]/ensure: created Info: Checking if redis-master exists Info: Creating kubernetes_service redis-master Notice: /Stage[main]/Main/Kubernetes_service[redis-master]/ensure: created Info: Checking if redis-master exists Info: Creating kubernetes_replication_controller redis-master Notice: /Stage[main]/Main/Kubernetes_replication_controller[redis-master]/ensure: created Info: Checking if redis-slave exists Info: Creating kubernetes_service redis-slave Notice: /Stage[main]/Main/Kubernetes_service[redis-slave]/ensure: created Info: Checking if redis-slave exists Info: Creating kubernetes_replication_controller redis-slave Notice: /Stage[main]/Main/Kubernetes_replication_controller[redis-slave]/ensure: created Notice: Finished catalog run in 2.61 seconds这里大概会有60s左右的时间完成guestbook所有实例的创建,一旦镜像下载完并且pod启动之后。你可以使用kubectl命令来找到负载均衡服务的IP地址:
$ kubectl get services frontend NAME LABELS SELECTOR IP(S) PORT(S) frontend name=frontend name=frontend 10.191.253.158 80/TCP 104.197.92.229 $ kubectl describe services frontend | grep "LoadBalancer Ingress" LoadBalancer Ingress: 104.197.92.229 整理Puppet声明的模块意味着我们可以做其他有意义的事情,像移除某些特定资源。在这个例子中,我们可以使用简单的配置来清除使用手册应用。对简单的资源,如下所示:
kubernetes_replication_controller { 'redis-master': ensure => absent, }这个模块的示例目录下有一个完整的配置用来删除所有操作手册应用。就像在本地使用如下命令:
$ puppet apply examples/guestbook-delete.pp --test ~/Documents/garethr-kubernetes Info: Loading facts Info: Loading facts Notice: Compiled catalog for pro.local in environment production in 0.27 seconds Info: Applying configuration version '1448445744' Info: Checking if frontend exists Info: Deleting kubernetes_service frontend Notice: /Stage[main]/Main/Kubernetes_service[frontend]/ensure: removed Info: Checking if frontend exists Info: Deleting kubernetes_replication_controller frontend Notice: /Stage[main]/Main/Kubernetes_replication_controller[frontend]/ensure: removed Info: Checking if redis-master exists Info: Deleting kubernetes_service redis-master Notice: /Stage[main]/Main/Kubernetes_service[redis-master]/ensure: removed Info: Checking if redis-master exists Info: Deleting kubernetes_replication_controller redis-master Notice: /Stage[main]/Main/Kubernetes_replication_controller[redis-master]/ensure: removed Info: Checking if redis-slave exists Info: Deleting kubernetes_service redis-slave Notice: /Stage[main]/Main/Kubernetes_service[redis-slave]/ensure: removed Info: Checking if redis-slave exists Info: Deleting kubernetes_replication_controller redis-slave Notice: /Stage[main]/Main/Kubernetes_replication_controller[redis-slave]/ensure: removed Notice: Finished catalog run in 2.56 seconds 结论以上只是演示了标准Kubernetes YAML格式和Puppet配置之间的基本相似的特征。我们已经看到仅对Service和RC的支持,但是还支持一些其他模块像Secrets,Volume,Quotas等。
使用Puppet管理Kubernetes的真正意义,在于构建封装和管理Kubernetes的状态。例如:
在以上的配置示例中,我们可以改变值和简单重分配配置(使用Puppet agent来实现)。例如,改变前端控制器的副本数量。 尽管没有修改配置,我们可以重新运行Puppet。在这种情况下,Puppet不会修改任何东西,并会告诉我们所有状态都如预期。 我们也注意到独立的配置有很多重复。使用简化的type,我们可以删掉那些重复的配置,并且把重要的变量作为操作手册的type参数。 Puppet语言同样有工作来校验和编写单元测试,像分发和共享可重用模块一样。