Kubernetes Cookbook 编程指南 中文版教程
创建时间:2018-12-07  访问量:3665  7  0

Kubernetes Cookbook 编程指南 中文版教程

保证容器的灵活使用

Pod,在Kubernetes中,意味着一组容器,它也是最小的计算单元。在前面章节中,你可能知道关于Pod的基本使用。Pod通常是由副本控制器管理的并由服务暴露;它们工作为此种场景下的应用程序。

在本节,我们将讨论两个新的特征:job和daemon set。这两个特征可以使Pod更高效的使用。

开始

什么是类job(job-like)的Pod和类daemon(daemon-like)的Pod?Kubernetes工作中的Pod将在完成工作后直接终止。另一方面,一个daemon-like的Pod将在每个节点上创建,而用户想让它长时间运行来服务于系统进程。

Job和daemon组都属于Kubernetes API的扩展。此外,在黙认的API设置中daemon设置类型是被禁用的。那么,为了后面的测试你需要启用它。daemon组的设置不需要启动,你就能获取一个关于未知类型的错误:

# kubectl create -f daemonset-test.yaml
error validating "daemonset-test.yaml": error validating data: couldn't
find type: v1beta1.DaemonSet; if you choose to ignore these errors, turn
validation off with --validate=false
Or error of this one
Error from server: error when creating "daemonset-free.yaml": the server
could not find the requested resource

为了在Kubernetes系统中启用Daemon组,你应该更新Kubernetes apiserver的进程中的一个标记:--runtime-config=extensions/v1beta1/daemonsets=true。修改你的服务脚本或配置选项:

// For service init.d scripts, attached the tag after command hyperkube
apiserver or kube-apiserver
# cat /etc/init.d/kubernetes-master
(heading lines ignored)
:
# Start daemon.
echo $"Starting apiserver: "
daemon $apiserver_prog \
--service-cluster-ip-range=${CLUSTER_IP_RANGE} \
--insecure-port=8080 \
--secure-port=6443 \
--basic-auth-file="/root/ba_file" \
--address=0.0.0.0 \
--etcd_servers=${ETCD_SERVERS} \
--cluster_name=${CLUSTER_NAME} \
--runtime-config=extensions/v1beta1/daemonsets=true \
> ${logfile}-apiserver.log 2>&1 &
:
(ignored)
// For systemd service management, edit configuration files by add the
tag as optional one
# cat /etc/kubernetes/apiserver
(heading lines ignored)
:
# Add your own!
KUBE_API_ARGS="--cluster_name=Happy-k8s-cluster --runtimeconfig=extensions/v1beta1/daemonsets=true"

在你设置了这个标记之后,删除/tmp/kubectl.schema目录,这个目录会缓存API的schema。然后,最好重启Kubernetes apiserver。

// Remove the schema file
# rm -f /tmp/kubectl.schema
// The method to restart apiserver for init.d script
# service kubernetes-master restart
// Or, restart the daemon for systemd service management
# systemd restart kube-apiserver
// After restart daemon apiserver, you can find daemonsets is enable in
your API server
# curl http://localhost:8080/apis/extensions/v1beta1
{
    "kind": "APIResourceList",
    "groupVersion": "extensions/v1beta1",
    "resources": [
        {
        	"name": "daemonsets",
        	"namespaced": true
        },
        {
        	"name": "daemonsets/status",
        	"namespaced": true
        },
:

接下来,下面的章节,我们将展示如何使用配置文件创建一个job和daemon组。查看一个本章中的配置文件的使用这一节来了解更多其它的概念:

它是如何工作的...

对我们来说是没有命令行接口来创奸一个job或一个daemon组。因此,我们将通过在一个模板文件中写所有的配置再构建这两个资源类型。

Pod作为一个作业(Job)

一个Job-like Pod适合于测试你的容器,它可以用于单元测试可集成测试;或者,它可以用于静态程序。就像下面的例子,我们将写一个job模板来验证ubuntu镜像中软件包的安装:

# cat job-dpkg.yaml
apiVersion: extensions/v1beta1
kind: Job
metadata:
	name: package-check
spec:
    selector:
        matchLabels:
            image: ubuntu
            test: dpkg
    template:
        metadata:
            labels:
                image: ubuntu
                test: dpkg
                owner: Amy
        spec:
            containers:
            - name: package-check
                image: ubuntu
                command: ["dpkg-query", "-l"]
                restartPolicy: Never

一个Job资源需要一个选择器来定义有哪些Pod应该被包含在这个Job中。如果模板中没有指定选择器,它将仅仅与Job标签相同。一个Job中的Pod创建的重启策略被设置为Never或OnFailure,因为一个job在成功完成后就会终止。

现在,你已准备好使用你的模板来创建一个job了:

# kubectl create -f job-dpkg.yaml
job "package-check" created

在提交这个请求文件之后,它可能会验证Pod和job的状态:

# kubectl get job
JOB CONTAINER(S) IMAGE(S) SELECTOR SUCCESSFUL
package-check package-check ubuntu image in (ubuntu),test in (dpkg) 1
// Check the job as well
# kubectl get pod
NAME READY STATUS RESTARTS AGE
package-check-jrry1 0/1 Pending 0 6s

你会发现会启动一个Pod来处理这个任务。这个Pod将在进程结束后快速停止。子命令logs可以帮助获取结果:

# kubectl logs package-check-gtyrc
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/
Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version
Architecture Description
+++-===============================-
================================-============-
====================================================================-
===========
ii adduser 3.113+nmu3ubuntu3 all
add and remove users and groups
ii apt 1.0.1ubuntu2.10
amd64 commandline package manager
ii apt-utils 1.0.1ubuntu2.10
amd64 package management related utility programs
ii base-files 7.2ubuntu5.3
amd64 Debian base system miscellaneous files
:
(ignored)

请先用子命令describe来检验job的package-check;Pod完成的确认信息和其它消息作为系统信息显示:

# kubectl describe job package-check

稍后,要删除刚刚创建的job作业,请使用名称停止它:

# kubectl stop job package-check
job "package-check" deleted

创建一个运行多个Pod的作业(job)

用户也可以决定在一个单独的Job中应该完成的任务数量。它有助于解决一些随机抽样的问题。在前面的示例中,让我们在同一个模板上尝试一下。我们需要添加spec.completions项来指明Pod的数量:

# cat job-dpkg.yaml
apiVersion: extensions/v1beta1
kind: Job
metadata:
	name: package-check
spec:
	completions: 3
    template:
        metadata:
            name: package-check-amy
            labels:
                image: ubuntu
                test: dpkg
                owner: Amy
        spec:
            containers:
            - name: package-check
                image: ubuntu
                command: ["dpkg-query", "-l"]
            restartPolicy: Never

然后,通过describe子命令查看一下这个Job作业是个什么样了的:

# kubectl describe job package-check
Name: package-check
Namespace: default
Image(s): ubuntu
Selector: image in (ubuntu),owner in (Amy),test in (dpkg)
Parallelism: 3
Completions: 3
Labels: image=ubuntu,owner=Amy,test=dpkg
Pods Statuses: 3 Running / 0 Succeeded / 0 Failed
No volumes.
Events:
FirstSeen LastSeen Count From SubobjectPath Reason Message
───────── ──────── ───── ──── ───────────── ────── ───────
6s 6s 1 {job } SuccessfulCreate Created pod: packagecheck-dk184
6s 6s 1 {job } SuccessfulCreate Created pod: packagecheck-3uwym
6s 6s 1 {job } SuccessfulCreate Created pod: packagecheck-eg4nl

正如你所见,创建了三个Pod来解决这个Job。同样,因为选择器部被删除了,所以它从标签复制了。

Pod作为一个守护进程组(daemon set)

如果创建了一个Kubernetes守护进程组,定义的Pod将被部署在每个独立的Node节点上。它保证每个运行中的容器为每个Node分配相同的资源。在这种情形下,容器通常以守护进程的方式工作。

例如,下面的模板有一个ubuntu镜像容器,保持半分钟检查一次内存的使用情况。我们将作为一个daemon set来构建它:

# cat daemonset-free.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
	name: ram-check
spec:
    selector:
        app: checkRam
        version: v1
    template:
        metadata:
            labels:
                app: checkRam
                owner: Amy
                version: v1
    spec:
        containers:
        - name: ubuntu-free
            image: ubuntu
            command: ["/bin/bash","-c","while true; do free; sleep 30; done"]
            restartPolicy: Always

作为一个job作业,选择器可以被忽略,但是它采用的是标签labels的值。我们将总是将守护进程组的重启策略设置为Always,这将保证每个节点都有Pod在运行。

daemon set的缩写为ds;在命令行接口使用使用这个简写是很方便的:

# kubectl create -f daemonset-free.yaml
daemonset "ram-check" created
# kubectl get ds
NAME CONTAINER(S) IMAGE(S) SELECTOR NODESELECTOR
ram-check ubuntu-free ubuntu app=checkRam,version=v1 <none>
// Go further look at the daemon set by "describe"
# kubectl describe ds ram-check
Name: ram-check
Image(s): ubuntu
Selector: app=checkRam,version=v1
Node-Selector: <none>
Labels: app=checkRam,owner=Amy,version=v1
Desired Number of Nodes Scheduled: 3
Current Number of Nodes Scheduled: 3
Number of Nodes Misscheduled: 0
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Events:
FirstSeen LastSeen Count From SubobjectPath Reason Message
───────── ──────── ───── ──── ───────────── ────── ───────
3m 3m 1 {daemon-set } SuccessfulCreate Created pod: ramcheck-bti08
3m 3m 1 {daemon-set } SuccessfulCreate Created pod: ramcheck-u9e5f
3m 3m 1 {daemon-set } SuccessfulCreate Created pod: ramcheck-mxry2

这里,我们有3个Pod分别运行在不同的Node中。他们仍然可以在Pod的通道中被识别:

# kubectl get pod --selector=app=checkRam
NAME READY STATUS RESTARTS AGE
ram-check-bti08 1/1 Running 0 4m
ram-check-mxry2 1/1 Running 0 4m
ram-check-u9e5f 1/1 Running 0 4m
// Get the evidence!

# kubectl describe pods --selector=app=checkRam -o wide
NAME READY STATUS RESTARTS AGE NODE
ram-check-bti08 1/1 Running 0 4m kube-node1
ram-check-mxry2 1/1 Running 0 4m kube-node3
ram-check-u9e5f 1/1 Running 0 4m kube-node2

最好使用logs子命令来评估输出结果 :

# kubectl logs ram-check-bti08
total used free shared buffers cached
Mem: 2051644 1256876 794768 148 136880 450620
-/+ buffers/cache: 669376 1382268
Swap: 0 0 0
total used free shared buffers cached
Mem: 2051644 1255888 795756 156 136912 450832
-/+ buffers/cache: 668144 1383500
Swap: 0 0 0
:
(ignored)

接下来,通过模板文件的引用或通过资源的名称来删除daemon set。

# kubectl stop -f daemonset-free.yaml
// or
# kubectl stop ds ram-check

仅在指定的Node上运行Daemon Set

还有一种方案可将deamon-like pod部署在指定的Node节点上。首先,你需要通过标记Node来将Node进行分组。我们将仅仅使用特定的键值对标签来为kube-node3这个节点进行标记,这标明了它是一个运行daemon set的Node:

# kubectl label nodes kube-node3 runDS=ok
node "kube-node3" labeled
# kubectl get nodes
NAME LABELS STATUS
AGE
kube-node1 kubernetes.io/hostname=kube-node1 Ready 27d
kube-node2 kubernetes.io/hostname=kube-node2 Ready 27d
kube-node3 kubernetes.io/hostname=kube-node3,runDS=ok Ready 4d

然后,我们将在模板中选择这个只有一个成员的组。spec.template.spec.nodeSelector项来为Node选择添加键值对:

# cat daemonset-free.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
	name: ram-check
spec:
    selector:
        app: checkRam
        version: v1
    template:
        metadata:
            labels:
                app: checkRam
                owner: Amy
                version: v1
        spec:
       		nodeSelector:
            	runDS: ok
            containers:
            - name: ubuntu-free
                image: ubuntu
                command: ["/bin/bash","-c","while true; do free; sleep 30; done"]
            restartPolicy: Always

当把这个daemon set分配给一个特定的Node分组时,我们可以在这个具有3节点系统的其中一个单独的节点上运行它:

# kubectl describe pods --selector=app=checkRam | grep "Node"
Node: kube-node3/10.96.219.251

它是如何工作的...

尽管job和daemon set是pod中的特殊工具集,在它与Pod之中Kubernetes系统有着不同的管理。

对于作业(job),它的选择器不会指向已存在的Pod。它惧怕将由副本控制器控制的Pod作为一个作业job。这个副本控制器有一个期望的Pod运行数量,这里Job的理想状态冲突:在它们完成任务后,pod应该删除。副本控制器中的Pod永远无法达到最终的期望的状态。

另一方面,与通用Pod不同,在一个daemon set中的一个Pod可以不需要Kubernetes调度就会被创建。这个概念很明显,因为守护进程集(daemon set)只考虑Node节点的标签,而不考虑它们的CPU或内存使用情况。

还可以参考

本节,我们深入探讨了一下Kubernetes Pod。同样,我们使用Kubernetes配置文件的一个分支。关于配置文件的这一节将使您了解有关以下内容的更多信息:

  • 第2章理解Kubernetes相关概念,Pod的使用

  • 配置文件的使用