目录 本文内容除第13章节外,已经基于k8s v1.8.8进行了验证测试。 1、Yaml格式的Pod定义文件完整模板详解apiVersion: v1 //版本 kind: pod //类型,pod metadata: //元数据 name: String //元数据,pod的名字 namespace: String //元数据,pod的命名空间 labels: //元数据,标签列表 - name: String //元数据,标签的名字 annotations: //元数据,自定义注解列表 - name: String //元数据,自定义注解名字 spec: //pod中容器的详细定义 containers: //pod中的容器列表,可以有多个容器 - name: String //容器的名称 image: String //容器中的镜像 imagesPullPolicy: [Always|Never|IfNotPresent]//获取镜像的策略,默认值为Always,每次都尝试重新下载镜像 command: [String] //容器的启动命令列表(不配置的话使用镜像内部的命令) args: [String] //启动参数列表 workingDir: String //容器的工作目录 volumeMounts: //挂载到到容器内部的存储卷设置 - name: String mountPath: String //存储卷在容器内部Mount的绝对路径 readOnly: boolean //默认值为读写 ports: //容器需要暴露的端口号列表 - name: String containerPort: int //容器要暴露的端口 hostPort: int //容器所在主机监听的端口(容器暴露端口映射到宿主机的端口,设置hostPort时同一台宿主机将不能再启动该容器的第2份副本) protocol: String //TCP和UDP,默认值为TCP env: //容器运行前要设置的环境列表 - name: String value: String resources: limits: //资源限制,容器的最大可用资源数量 cpu: Srting memory: String requeste: //资源限制,容器启动的初始可用资源数量 cpu: String memory: String livenessProbe: //pod内容器健康检查的设置 exec: command: [String] //exec方式需要指定的命令或脚本 httpGet: //通过httpget检查健康 path: String port: number host: String scheme: Srtring httpHeaders: - name: Stirng value: String tcpSocket: //通过tcpSocket检查健康 port: number initialDelaySeconds: 0//首次检查时间 timeoutSeconds: 0 //检查超时时间 periodSeconds: 0 //检查间隔时间 successThreshold: 0 failureThreshold: 0 securityContext: //安全配置 privileged: falae restartPolicy: [Always|Never|OnFailure]//重启策略,默认值为Always nodeSelector: object //节点选择,表示将该Pod调度到包含这些label的Node上,以key:value格式指定 imagePullSecrets: - name: String hostNetwork: false //是否使用主机网络模式,弃用Docker网桥,默认否 volumes: //在该pod上定义共享存储卷列表 - name: String emptyDir: {} //是一种与Pod同生命周期的存储卷,是一个临时目录,内容为空 hostPath: //Pod所在主机上的目录,将被用于容器中mount的目录 path: string secret: //类型为secret的存储卷 secretName: String item: - key: String path: String configMap: //类型为configMap的存储卷 name: String items: - key: String path: String 详细说明表:
2、Pod的基本用法在k8s中对运行容器的要求为:容器的主程序需要一直在前台运行,而不是后台运行。应用需要改造成前台运行的方式。如果改造应用上存在困难,则可以通过supervisor的进程管理工具,即supervisor在前台运行,应用程序由supervisor管理在后台运行。 如果我们创建的Docker镜像的启动命令是后台执行程序,则在kubelet创建包含这个容器的pod之后运行完该命令,即认为Pod已经结束,将立刻销毁该Pod。如果为该Pod定义了RC,则创建、销毁会陷入一个无限循环的过程中。 Pod可以由1个或多个容器组成。 2.1 由1个容器组成的Pod示例 frontend-env-pod.yaml apiVersion: v1 kind: Pod metadata: name: frontend labels: name: frontend spec: containers: - name: frontend image: kubeguide/guestbook-php-frontend env: - name: GET_HOSTS_FROM value: env ports: - containerPort: 80 执行创建命令,观察创建pod的结果: [root@bogon ~]# kubectl create -f frontend-env-pod.yaml pod "frontend" created [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE frontend 0/1 ContainerCreating 0 8s mysql-tjvjl 1/1 Running 1 8d mysql2-lmxwm 1/1 Running 1 8d [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE frontend 1/1 Running 0 46m mysql-tjvjl 1/1 Running 1 8d mysql2-lmxwm 1/1 Running 1 8d [root@bogon ~]# kubectl describe pod frontend Name: frontend Namespace: default Node: 10.0.2.6/10.0.2.6 Start Time: Mon, 05 Mar 2018 09:08:54 +0800 Labels: name=frontend Annotations: <none> Status: Running IP: 172.17.0.4 Containers: frontend: Container ID: docker://c835a9e2b824ed4ddf667634ef7ec461787286fb2b65a1b3dc6f55b043b120c4 Image: kubeguide/guestbook-php-frontend Image ID: docker-pullable://kubeguide/guestbook-php-frontend@sha256:195181e0263bcee4ae0c3e79352bbd3487224c0042f1b9ca8543b788962188ce Port: 80/TCP State: Running Started: Mon, 05 Mar 2018 09:11:47 +0800 Ready: True Restart Count: 0 Environment: GET_HOSTS_FROM: env Mounts: <none> Conditions: Type Status Initialized True Ready True PodScheduled True Volumes: <none> QoS Class: BestEffort Node-Selectors: <none> Tolerations: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 46m default-scheduler Successfully assigned frontend to 10.0.2.6 Normal Pulling 46m kubelet, 10.0.2.6 pulling image "kubeguide/guestbook-php-frontend" Normal Pulled 44m kubelet, 10.0.2.6 Successfully pulled image "kubeguide/guestbook-php-frontend" Normal Created 44m kubelet, 10.0.2.6 Created container Normal Started 44m kubelet, 10.0.2.6 Started container 2.2 由两个为紧耦合关系的容器打包组成的Pod示例 例如,当frontend和redis两个容器应用为紧耦合关系,此时应组成一个整体对外提供服务,应选择将二者打包为一个Pod。同个Pod中的多个容器之间互相访问可以通过localhost来通信。 在下面的例子中,frontend容器中的应用可以直接通过访问localhost:6379对同属一个Pod内的redis-master服务进行访问。 frontend-localredis-pod.yaml apiVersion: v1 kind: Pod metadata: name: redis-php labels: name: redis-php spec: containers: - name: frontend image: kubeguide/guestbook-php-frontend:localredis ports: - containerPort: 80 - name: redis image: kubeguide/redis-master ports: - containerPort: 6379 执行创建命令,观察创建pod的结果: [root@bogon ~]# kubectl create -f frontend-localredis-pod.yaml pod "redis-php" created [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE frontend 1/1 Running 0 1h mysql-tjvjl 1/1 Running 1 8d mysql2-lmxwm 1/1 Running 1 8d redis-php 2/2 Running 0 16m [root@bogon ~]# kubectl describe pod redis-php Name: redis-php Namespace: default Node: 10.0.2.6/10.0.2.6 Start Time: Mon, 05 Mar 2018 10:00:00 +0800 Labels: name=redis-php Annotations: <none> Status: Running IP: 172.17.0.5 Containers: frontend: Container ID: docker://ef8b0ef47c41b7e77a3ab905081d18c29ed613b0a7e355887a667b54e9c0b63f Image: kubeguide/guestbook-php-frontend:localredis Image ID: docker-pullable://kubeguide/guestbook-php-frontend@sha256:37c2c1dcfcf0a51bf9531430fe057bcb1d4b94c64048be40ff091f01e384f81e Port: 80/TCP State: Running Started: Mon, 05 Mar 2018 10:00:03 +0800 Ready: True Restart Count: 0 Environment: <none> Mounts: <none> redis: Container ID: docker://9cba46735bd24e4a75570c7025729433ff10f5cc6b13613e7e525865a05b6c8d Image: kubeguide/redis-master Image ID: docker-pullable://kubeguide/redis-master@sha256:e11eae36476b02a195693689f88a325b30540f5c15adbf531caaecceb65f5b4d Port: 6379/TCP State: Running Started: Mon, 05 Mar 2018 10:04:03 +0800 Ready: True Restart Count: 0 Environment: <none> Mounts: <none> Conditions: Type Status Initialized True Ready True PodScheduled True Volumes: <none> QoS Class: BestEffort Node-Selectors: <none> Tolerations: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 16m default-scheduler Successfully assigned redis-php to 10.0.2.6 Normal Pulling 16m kubelet, 10.0.2.6 pulling image "kubeguide/guestbook-php-frontend:localredis" Normal Pulled 15m kubelet, 10.0.2.6 Successfully pulled image "kubeguide/guestbook-php-frontend:localredis" Normal Created 15m kubelet, 10.0.2.6 Created container Normal Started 15m kubelet, 10.0.2.6 Started container Normal Pulling 15m kubelet, 10.0.2.6 pulling image "kubeguide/redis-master" Normal Pulled 11m kubelet, 10.0.2.6 Successfully pulled image "kubeguide/redis-master" Normal Created 11m kubelet, 10.0.2.6 Created container Normal Started 11m kubelet, 10.0.2.6 Started container 登录到容器frontend中,查看在redis容器中的6379服务端口,看上去就像是自己本地系统的服务监听端口一样: [root@bogon ~]# kubectl exec -it redis-php -c frontend /bin/bash root@redis-php:/var/www/html# ss -an|grep 6379 \tcp LISTEN 0 128 *:6379 *:* tcp LISTEN 0 128 :::6379 :::* root@redis-php:/var/www/html# 3、静态Pod静态 pod 在特定的节点上直接通过 kubelet 守护进程进行管理,API 服务无法管理。它没有跟任何的副本控制器进行关联,kubelet 守护进程对它进行监控,如果崩溃了,kubelet 守护进程会重启它。 Kubelet 通过 Kubernetes API 服务为每个静态 pod 创建 镜像 pod,这些镜像 pod 对于 API 服务是可见的,但是不受它控制。 静态 pod 能够通过两种方式创建:配置文件或者 HTTP。 3.1 配置文件方式
例如,配置目录为/etc/kubelet.d/,为kubelet添加启动参数:--pod-manifest-path=/etc/kubelet.d/,在该目录下放入static-web.yaml。 apiVersion: v1 kind: Pod metadata: name: static-web labels: name: static-web spec: containers: - name: static-web image: nginx ports: - name: web containerPort: 80 放入上面的yaml文件后,即可从k8s上看到正在创建名为static-web-10.0.2.6的Pod: [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE frontend 1/1 Running 1 11h mysql-tjvjl 1/1 Running 2 8d mysql2-lmxwm 1/1 Running 2 8d redis-php 2/2 Running 2 10h static-web-10.0.2.6 0/1 ContainerCreating 0 13s [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE frontend 1/1 Running 1 11h mysql-tjvjl 1/1 Running 2 8d mysql2-lmxwm 1/1 Running 2 8d redis-php 2/2 Running 2 10h static-web-10.0.2.6 1/1 Running 0 4m 3.2 HTTP方式 Kubelet 定期的从参数 --manifest-url=<URL> 配置的地址下载文件,并将其解析为 json/yaml 格式的 pod 描述。它的工作原理与从 --pod-manifest-path=<directory> 中发现文件执行创建/更新静态 pod 是一样的,即,文件的每次更新都将应用到运行中的静态 pod 中。 4、Pod容器共享Volume同一个Pod中的多个容器可以共享Pod级别的存储卷Volume,Volume可以定义为各种类型,多个容器各自进行挂载,将Pod的Volume挂载为容器内部需要的目录。 例如:Pod级别的Volume:”app-logs”,用于tomcat向其中写日志文件,busybox读日志文件。 pod-volumes-applogs.yaml apiVersion: v1 kind: Pod metadata: name: volume-pod spec: containers: - name: tomcat image: tomcat ports: - containerPort: 8080 volumeMounts: - name: app-logs mountPath: /usr/local/tomcat/logs - name: busybox image: busybox command: ["sh","-c","tail -f /logs/catalina*.log"] volumeMounts: - name: app-logs mountPath: /logs volumes: - name: app-logs emptuDir: {} 创建并通过容器“busybox”挂载的共享卷来查看tomcat应用的日志: [root@bogon ~]# kubectl create -f pod-volumes-applogs.yaml pod "volume-pod" created [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE frontend 1/1 Running 1 12h mysql-tjvjl 1/1 Running 2 8d mysql2-9bfph 1/1 Running 0 21m volume-pod 2/2 Running 0 6s [root@bogon ~]# kubectl logs volume-pod -c busybox 05-Mar-2018 13:27:20.781 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/docs] has finished in [12] ms 05-Mar-2018 13:27:20.781 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/examples] 05-Mar-2018 13:27:21.069 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/examples] has finished in [287] ms 05-Mar-2018 13:27:21.069 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/host-manager] 05-Mar-2018 13:27:21.106 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/host-manager] has finished in [36] ms 05-Mar-2018 13:27:21.106 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/manager] 05-Mar-2018 13:27:21.122 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/manager] has finished in [16] ms 05-Mar-2018 13:27:21.126 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 05-Mar-2018 13:27:21.171 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"] 05-Mar-2018 13:27:21.175 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 684 ms 查看容器“tomcat”中的应用日志目录,以及日志文件内容: [root@bogon ~]# kubectl exec -it volume-pod -c tomcat -- ls /usr/local/tomcat/logs catalina.2018-03-05.log localhost_access_log.2018-03-05.txt host-manager.2018-03-05.log manager.2018-03-05.log localhost.2018-03-05.log [root@bogon ~]# kubectl exec -it volume-pod -c tomcat -- tail /usr/local/tomcat/logs/catalina.2018-03-05.log 05-Mar-2018 13:27:20.781 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/docs] has finished in [12] ms 05-Mar-2018 13:27:20.781 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/examples] 05-Mar-2018 13:27:21.069 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/examples] has finished in [287] ms 05-Mar-2018 13:27:21.069 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/host-manager] 05-Mar-2018 13:27:21.106 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/host-manager] has finished in [36] ms 05-Mar-2018 13:27:21.106 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/manager] 05-Mar-2018 13:27:21.122 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/manager] has finished in [16] ms 05-Mar-2018 13:27:21.126 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 05-Mar-2018 13:27:21.171 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"] 05-Mar-2018 13:27:21.175 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 684 ms 5、Pod的配置管理应用部署的一个最佳实践是将应用所需的配置信息与程序进行分离。将应用打包为容器镜像后,可以通过环境变量或外挂文件的方式,在创建容器时进行配置注入。 Kubernetes v1.2的版本提供统一的集群配置管理方案–ConfigMap。ConfigMap用于保存配置数据的键值对,可以用来保存单个属性,也可以用来保存配置文件。ConfigMap跟secret很类似,但它可以更方便地处理不包含敏感信息的字符串。 5.1 ConfigMap概述 典型使用场景:
ConfigMap以一个或多个key:value的形式保存在kubernetes系统中供应用使用,既可以表示一个变量的值(例如:apploglevel=info),也可以表示完整配置文件的内容(例如server.xml=<?xml...>...)。 可以通过yaml配置文件或直接使用kubectl create configmap命令行的方式来创建ConfigMap。 5.2 使用ConfigMap的局限
5.3 创建ConfigMap资源对象 1)通过yaml配置文件方式创建 [root@bogon ~]# more cm-appvars.yaml apiVersion: v1 kind: ConfigMap metadata: name: cm-appvars data: apploglevel: info appdatadir: /var/date 创建并查看结果: [root@bogon ~]# kubectl create -f cm-appvars.yaml configmap "cm-appvars" created [root@bogon ~]# kubectl get configmap NAME DATA AGE cm-appvars 2 16s [root@bogon ~]# kubectl describe configmap cm-appvars Name: cm-appvars Namespace: default Labels: <none> Annotations: <none> Data ==== apploglevel: ---- info appdatadir: ---- /var/date Events: <none> [root@bogon ~]# kubectl get configmap cm-appvars -o yaml apiVersion: v1 data: appdatadir: /var/date apploglevel: info kind: ConfigMap metadata: creationTimestamp: 2018-03-05T16:02:05Z name: cm-appvars namespace: default resourceVersion: "522740" selfLink: /api/v1/namespaces/default/configmaps/cm-appvars uid: 8cb9bada-208e-11e8-9f54-080027cf1a4c 2)通过yaml配置文件方式直接将一个应用的配置文件定义为一个ConfigMap 定义一个ConfigMap 配置文件 cm-jdbcproperties.yaml apiVersion: v1 kind: ConfigMap metadata: name: cm-jdbcproperties data: key-jdbcproperties: | JDBC_DRIVER_CLASS_NAME=com.mysql.jdbc.Driver JDBC_URL=jdbc:mysql://localhost:3306/bz_argon?useUnicode=true&characterEncoding=utf8 JDBC_USER_NAME=root JDBC_PASSWORD=123456 JDBC_INITIALSIZE=10 JDBC_MAXACTIVE=20 JDBC_MAXIDLE=20 JDBC_MINIDLE=10 JDBC_MAXWAIT=60000 JDBC_VALIDATIONQUERY=SELECT 1 FROM DUAL JDBC_TESTONBORROW=false JDBC_TESTONRETURN=false JDBC_TESTWHILEIDLE=true JDBC_TIMEBETWEENEVICTIONRUNSMILLIS=6000 JDBC_MINEVICTABLEIDLETIMEMILLIS=25200000 JDBC_REMOVEABANDONED=true JDBC_REMOVEABANDONEDTIMEOUT=1800 JDBC_LOGABANDONED=true 创建并查看结果: [root@bogon ~]# kubectl create -f cm-jdbcproperties.yaml configmap "cm-jdbcproperties" created [root@bogon ~]# kubectl get configmap cm-jdbcproperties NAME DATA AGE cm-jdbcproperties 1 29s [root@bogon ~]# kubectl describe configmap cm-jdbcproperties Name: cm-jdbcproperties Namespace: default Labels: <none> Annotations: <none> Data ==== key-jdbcproperties: ---- JDBC_DRIVER_CLASS_NAME=com.mysql.jdbc.Driver JDBC_URL=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 JDBC_USER_NAME=root JDBC_PASSWORD=123456 JDBC_INITIALSIZE=10 JDBC_MAXACTIVE=20 JDBC_MAXIDLE=20 JDBC_MINIDLE=10 JDBC_MAXWAIT=60000 JDBC_VALIDATIONQUERY=SELECT 1 FROM DUAL JDBC_TESTONBORROW=false JDBC_TESTONRETURN=false JDBC_TESTWHILEIDLE=true JDBC_TIMEBETWEENEVICTIONRUNSMILLIS=6000 JDBC_MINEVICTABLEIDLETIMEMILLIS=25200000 JDBC_REMOVEABANDONED=true JDBC_REMOVEABANDONEDTIMEOUT=1800 JDBC_LOGABANDONED=true Events: <none> 3)通过kubectl命令行方式创建 通过--from-file参数从文件中进行创建,可以指定key的名称,也可以在一个命令行中创建包含多个key的ConfigMap。 kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source 通过--from-file参数从目录中进行创建,该目录下的每个配置文件名被设置为key,文件内容被设置为value。 kubectl create configmap NAME --from-file=config-files-dir 通过--from-literal从文本中进行创建,直接将指定的key=value创建为ConfigMap的内容。 kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2 例如: $ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm $ kubectl create configmap env-config --from-literal=log_level=INFO 5.4 在Pod中使用ConfigMap 容器应用对ConfigMap的使用有两种方法:
1)通过环境变量使用ConfigMap方式一 定义一个Pod:cm-test-pod.yaml,使用上面定义过的"cm-appvars" apiVersion: v1 kind: Pod metadata: name: cm-test-pod spec: containers: - name: cm-test image: busybox command: [ "/bin/sh", "-c", "env|grep APP" ] env: - name: APPLOGLEVEL #定义环境变量名称 valueFrom: configMapKeyRef: name: cm-appvars #使用上面定义过的"cm-appvars" ConfigMap key: apploglevel - name: APPDATADIR #定义环境变量名称 valueFrom: configMapKeyRef: name: cm-appvars #使用上面定义过的"cm-appvars" ConfigMap key: appdatadir 创建: [root@bogon ~]# kubectl create -f cm-test-pod.yaml [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE cm-test-pod 0/1 Completed 2 28s 查看cm-test-pod是否已经获取到了指定的环境变量: [root@bogon ~]# kubectl logs cm-test-pod APPDATADIR=/var/date APPLOGLEVEL=info 2)通过环境变量使用ConfigMap方式二 从k8s 1.6开始,新引入了一个字段envFrom,实现在Pod环境内将ConfigMap中所有定义的key=value自动生成为环境变量。 方法如下。 定义一个Pod:cm-test-pod2.yaml,使用上面定义过的"cm-appvars" apiVersion: v1 kind: Pod metadata: name: cm-test-pod2 spec: containers: - name: cm-test image: busybox command: [ "/bin/sh", "-c", "env" ] envFrom: - configMapRef name: cm-appvars #根据cm-appvars中的key=value自动生成环境变量 restartPolicy: Never 再例如: apiVersion: v1 kind: Pod metadata: name: test-pod spec: containers: - name: test-container image: busybox command: [ "/bin/sh", "-c", "env" ] env: - name: SPECIAL_LEVEL_KEY valueFrom: configMapKeyRef: name: special-config key: special.how - name: SPECIAL_TYPE_KEY valueFrom: configMapKeyRef: name: special-config key: special.type envFrom: - configMapRef: name: env-config restartPolicy: Never 3)使用volume将ConfigMap作为文件或目录直接挂载 在5.3第2段内容中我们定义了一个cm-jdbcproperties.yaml文件。在这里我们将该ConfigMap中的内容以文件的形式mount到容器内部的/configfiles目录中去。 定义一个Pod:cm-test-app.yaml apiVersion: v1 kind: Pod metadata: name: cm-test-app spec: containers: - name: cm-test-app image: tomcat ports: - containerPort: 8080 volumeMounts: - name: jdbcproperties #引用volume的名称 mountPath: /configfiles #挂载到容器内的目录 volumes: - name: jdbcproperties #定义volume的名称 configMap: name: cm-jdbcproperties #使用ConfigMap "cm-jdbcproperties" items: - key: key-jdbcproperties #key=key-jdbcproperties path: jdbc.properties #value将以jdbc.properties的文件名进行挂载 创建Pod并进入容器查看配置文件: [root@bogon ~]# kubectl create -f cm-test-app.yaml [root@bogon ~]# kubectl exec -it cm-test-app -c cm-test-app /bin/bash root@cm-test-app:/# cd configfiles/ root@cm-test-app:/configfiles# ls jdbc.properties root@cm-test-app:/configfiles# more jdbc.properties JDBC_DRIVER_CLASS_NAME=com.mysql.jdbc.Driver JDBC_URL=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 JDBC_USER_NAME=root JDBC_PASSWORD=123456 ...... 5.5 其它注意事项
6、在容器内获取Pod信息(Downward API)Downward API可以使用以下2种方式把Pod信息注入容器内部:
6.1 环境变量方式——将Pod信息注入为环境变量 下面例子中通过Downward API将Pod的IP、名称和所在Namespace注入容器的环境变量中。 dapi-test-pod.yaml apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: busybox command: [ "/bin/sh", "-c", "env" ] env: - name: MY_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: MY_POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: MY_POD_IP valueFrom: fieldRef: fieldPath: status.podIP restartPolicy: Never 执行创建Pod命令: [root@bogon ~]# kubectl create -f dapi-test-pod.yaml pod "dapi-test-pod" created 查看Pod内容器打印的环境变量日志: [root@bogon ~]# kubectl logs dapi-test-pod KUBERNETES_SERVICE_PORT=443 KUBERNETES_PORT=tcp://10.10.10.1:443 HOSTNAME=dapi-test-pod SHLVL=1 HOME=/root MY_POD_NAMESPACE=default MY_POD_IP=172.17.0.8 MY_POD_NAME=dapi-test-pod ............... 注:valueFrom是Downward API 的一种特殊语法,在前面的ConfigMap中也有使用到。 6.2 环境变量方式——将容器资源信息注入为环境变量 下面例子中通过Downward API将Container的资源请求和限制信息注入到容器的环境变量中,容器中使用printenv命令把这些环境变量信息打印出来。 dapi-test-pod-container-vars.yaml apiVersion: v1 kind: Pod metadata: name: dapi-test-pod-container-vars spec: containers: - name: test-container image: busybox imagePullPolicy: Never command: [ "/bin/sh", "-c" ] args: - while true; do echo -en '\n'; printenv MY_CPU_REQUEST MY_CPU_LIMIT; printenv MY_MEM_REQUEST MY_MEM_LIMIT; sleep 3600; done; resources: requests: memory: "32Mi" cpu: "125m" limits: memory: "64Mi" cpu: "250m" env: - name: MY_CPU_REQUEST valueFrom: resourceFieldRef: containerName: test-container resource: requests.cpu - name: MY_CPU_LIMIT valueFrom: resourceFieldRef: containerName: test-container resource: limits.cpu - name: MY_MEM_REQUEST valueFrom: resourceFieldRef: containerName: test-container resource: requests.memory - name: MY_MEM_LIMIT valueFrom: resourceFieldRef: containerName: test-container resource: limits.memory restartPolicy: Never 创建pod和查看容器打印的环境变量信息: [root@bogon ~]# kubectl create -f dapi-test-pod-container-vars.yaml [root@bogon ~]# kubectl logs dapi-test-pod-container-vars 1 1 33554432 67108864 6.3 Volume挂载方式实现注入 在Pod定义文件中,在volumes中使用downwardAPI的特殊语法,通过items的设置,将会以path的名称生成文件。 下面的例子中,通过DownwardAPI将Pod的Label、Annotation列表通过Volume挂载为容器内的一个文件。容器应用使用echo命令将文件内容打印到标准输出中。 dapi-test-pod-volume.yaml apiVersion: v1 kind: Pod metadata: name: dapi-test-pod-volume labels: zone: us-est-coast cluster: test-cluster1 rack: rack-22 annotations: build: two builder: john-doe spec: containers: - name: test-container image: busybox imagePullPolicy: Never command: [ "/bin/sh", "-c" ] args: - while true; do echo -en '\n'; if [[ -e /etc/labels ]]; then echo -en '\n\n'; cat /etc/labels; fi; if [[ -e /etc/annotations ]]; then echo -en '\n\n'; cat /etc/annotations; fi; sleep 3600; done; volumeMounts: - name: podinfo mountPath: /etc readOnly: false volumes: - name: podinfo downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels - path: "annotations" fieldRef: fieldPath: metadata.annotations 创建Pod并查看容器打印的日志: [root@bogon ~]# kubectl create -f dapi-test-pod-volume.yaml pod "dapi-test-pod-volume" created [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE cm-test-app 1/1 Running 0 17h cm-test-pod 0/1 CrashLoopBackOff 222 18h dapi-test-pod-container-vars 1/1 Running 0 10h dapi-test-pod-volume 1/1 Running 0 6s frontend 1/1 Running 1 1d mysql-tjvjl 1/1 Running 2 9d mysql2-9bfph 1/1 Running 0 22h volume-pod 2/2 Running 0 22h [root@bogon ~]# kubetl logs dapi-test-pod-volume -bash: kubetl: command not found [root@bogon ~]# kubectl logs dapi-test-pod-volume cluster="test-cluster1" rack="rack-22" zone="us-est-coast" build="two" builder="john-doe" /config.seen="2018-03-06T19:28:41.715324795+08:00" DownwardAPI的使用价值: 为某些容器应用提供一些必需的应用初始化参数信息。例如在某些集群中,集群中的每个节点都需要将自身的标识及进程绑定的IP地址等信息事先写入配置文件中。容器中的进程在启动时读取这些信息,然后发布到某个类似服务注册中心的地方,以实现集群节点的自动发现功能。这正是DownwardAPI很好的一个使用场景。 7、Pod生命周期和重启策略7.1 Pod的状态
7.2 Pod的重启策略
Pod的重启策略受管理Pod的控制的直接影响,可以管理Pod的控制器有Replication Controller,Job,DaemonSet,及kubelet(静态Pod)。
7.3 常见的状态转换场景
8、Pod健康检查Pod的健康状态由两类探针来检查:LivenessProbe和ReadinessProbe。 8.1 LivenessProbe
kubelet定期执行LivenessProbe探针来判断容器的健康状态。 LivenessProbe参数:
8.2 LivenessProbe三种实现方式 1)ExecAction 在一个容器内部执行一个命令,如果该命令状态返回值为0,则表明容器健康。 apiVersion: v1 kind: Pod metadata: name: liveness-exec spec: containers: - name: liveness image: busybox args: - /bin/sh - -c - echo ok > /tmp/health;sleep 10;rm -fr /tmp/health;sleep 600 livenessProbe: exec: command: - cat - /tmp/health initialDelaySeconds: 15 timeoutSeconds: 1 12345678910111213141516171819 2)TCPSocketAction 通过容器IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。 apiVersion: v1 kind: Pod metadata: name: pod-with-healthcheck spec: containers: - name: nginx image: nginx ports: - containnerPort: 80 livenessProbe: tcpSocket: port: 80 initialDelaySeconds: 15 timeoutSeconds: 1 123456789101112131415 3)HTTPGetAction 通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于等于400,则认为容器健康。 apiVersion: v1 kind: Pod metadata: name: pod-with-healthcheck spec: containers: - name: nginx image: nginx ports: - containnerPort: 80 livenessProbe: httpGet: path: /_status/healthz port: 80 initialDelaySeconds: 15 timeoutSeconds: 1 8.3 ReadinessProbe
9、Pod调度管理在kubernetes系统中,pod在大部分场景下都只是容器的载体而已,通常需要通过Deployment,DaemonSet,Job等对象来完成Pod的调度与自动控制功能。 9.1 Deployment/RC:全自动调度 从调度策略上来说,这3个nginx Pod由系统全自动完成调度。它们各自最终运行在哪个节点上,完全由Master的Scheduler经过一系列算法计算得出,用记无法干预调度过程和结果。 示例: Deployment文件nginx-deployment.yaml apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 [root@bogon ~]# kubectl create -f nginx-deployment.yaml deployment "nginx-deployment" created [root@bogon ~]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 6s 查看已创建的ReplicaSet和Pod的信息: [root@bogon ~]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-5b4b59b4b8 3 3 3 1m [root@bogon ~]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-deployment-5b4b59b4b8-6l2rv 1/1 Running 0 50s nginx-deployment-5b4b59b4b8-s4czw 1/1 Running 0 50s nginx-deployment-5b4b59b4b8-w8sqn 1/1 Running 0 50s 9.2 NodeSelector: 定向调度 kubernetes中的Schduler 负责实现pode的调度,他会根据一些复杂的算法,把pod调度到某一个Node上,如果你想指定某个Pod需要指定在某个Node上则可以通过NodeSelector定向调度。 首先,需要为目标Node打上一些标签: [root@bogon ~]# kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME 10.0.2.6 Ready <none> 9d v1.8.8 <none> CentOS Linux 7 (Core) 3.10.0-693.17.1.el7.x86_64 docker://17.12.0-ce [root@bogon ~]# kubectl label nodes 10.0.2.6 zone=north node "10.0.2.6" labeled 然后,在Pod的定义中加上nodeSelector的设置,例如: [root@bogon ~]# more nodeselector-pod.yaml apiVersion: v1 kind: Pod metadata: name: pod-with-healthcheck spec: containers: - name: nginx image: nginx ports: - containerPort: 80 nodeSelector: zone: north [root@bogon ~]# kubectl create -f nodeselector-pod.yaml pod "pod-with-healthcheck" created [root@bogon ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-with-healthcheck 1/1 Running 0 18s 172.17.0.7 10.0.2.6 如果我们给多个Node都定义了相同的标签,则scheduler将会根据调度算法从这组Node中挑选一个可用的进行Pod调度。 通过基于Node标签的调度试,我们可以把集群中具有不同特点的Node贴上不同的标签,如“role=frontend”,“role=backend”,“role=database”等标签。在部署应用时就可以根据应用的需求设置NodeSelector来进行指定Node范围的调度。 注:如果我们指定了Podr nodeSelector条件,但集群中不存在符合条件的Node,则最终这个Pod无法被成功调度。 Kubernetes为Node提供了一些预定义的内置标签可以使用:
9.3 NodeAffinity:Node亲和性调度 亲和性调度机制极大地扩展了Pod的调度能力,主要增强的功能有:
NodeAffinity意为Node亲和性调度策略,较NodeSelector更为精确匹配。NodeAffinity是条件范围匹配,通过In(属于)、NotIn(不属于)、Exists(存在一个条件)、DoesNotExist(不存在)、Gt(大于)、Lt(小于)等操作符来选择Node,使调度更加灵活。 NodeAffinity目前有两种节点亲和性表达式:
NodeAffinity规则设置注意事项:
示例: apiVersion: v1 kind: Pod metadata: name: pod-affinity-example spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: /hostname operator: In values: - k8s-node01 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: /hostname operator: NotIn values: - k8s-master01 - k8s-master02 containers: - name: example image: gcr.io/google_containers/pause:2.0 定义描述:
9.4 PodAffinity:Pod亲和与互斥调度策略 podAffinity基于Pod的标签来选择Node,仅调度到满足条件Pod所在的Node上,支持podAffinity和podAntiAffinity。 匹配的表达式有,In, NotIn, Exists, DoesNotExist,通过该策略,可以更灵活地对Pod进行调度。例如,将多实例的Pod分散到不通的Node、尽量调度A-Pod到有B-Pod运行的Node节点上等等。 另外与Node-affinity不同的是,该策略是依据Pod的Label进行调度,所以会受到namespace约束。 与 node affinity 相似,pod affinity 也有 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution,意义也和之前一样。如果有使用亲和性,在 affinity 下面添加 podAffinity 字段,如果要使用互斥性,在 affinity 下面添加 podAntiAffinity 字段。 podAffinity 配置规则描述:
topologyKey的使用约束:
示例: 1)先创建一个参照目标Pod 创建一个名为pod-flag的Pod,带有标签security=S1和app=nginx。后面的例子将使用pod-flag作为Pod亲和与互斥的目标Pod。 pod-flag.yaml apiVersion: v1 kind: Pod metadata: name: pod-flag labels: security: "S1" app: "nginx" spec: containers: - name: nginx image: nginx 2)Pod的亲和性调度 创建第2个Pod来说明Pod的亲和性调度,这里使用的亲和标签是security=S1,对应上面的Pod“pod-flag”,topologyKey的值被设置为“/hostname”。 pod-affinity.yaml apiVersion: v1 kind: Pod metadata: name: pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: /hostname containers: - name: with-pod-affinity image: gcr.io/google_containers/pause-amd64:3.0 创建pod-affinity后,可以使用kubectl get pods -o wide查看一下是不是和第一步骤中的pod-flag分配在同一个Node节点上了。 3)Pod的互斥性调度 创建第3个Pod,我们希望它不能与参照目标Pod运行在同一个Node上。 anti-affinity.yaml apiVersion: v1 kind: Pod metadata: name: anti-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: failure-domain.beta./zone podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: /hostname containers: - name: anti-affinity image: gcr.io/google_containers/pause-amd64:3.0 这里要求这个新Pod与security=S1的Pod为同一个zone,但是不与app=nginx的Pod为同一个Node。zone是事先给Node所打一标签,位于同一个zone中的多个Node会都打上一个相同值的zone标签。 创建之后,使用kubectl get pods -o wide来查看,是不是被调度到了同一zone中的其Node上去了。 注:上面第3步骤中的实验暂未通过测试,创建Pod报错显示为找不到符合匹配条件的Nodes,问题待解决。 注:列出 node 的时候指定 --show-labels 参数就能查看 node 都添加了哪些 label [root@bogon ~]# kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS 10.0.2.10 Ready <none> 32m v1.8.8 beta./arch=amd64,beta./os=linux,/hostname=10.0.2.10,zone=north 10.0.2.6 Ready <none> 10d v1.8.8 beta./arch=amd64,beta./os=linux,/hostname=10.0.2.6,zone=north 9.5 Taints和Tolerations(污点和容忍) 概念:
1)可以在命令行为Node节点添加Taints kubectl taint nodes node1 key=value:NoSchedule 2)在Pod上声明Toleration,有两种声明的语法 tolerations: - key: "key" operator: "Equal" value: "value" effect: "NoSchedule" 或者: tolerations: - key: "key" operator: "Exists" effect: "NoSchedule" 3)Pod的Toleration声明中几个关键字的使用方法
4)effect可以定义为
注:tolerationSeconds,表明一个pod在被驱逐前的宽限时间。如果在这个宽限期内,Taint被移除,则不会触发驱逐事件。 Node和Pod上都可以定义多个Taints和Tolerations,Scheduler会根据具体定义进行筛选,Node筛选Pod列表的时候,会保留Tolerations定义匹配的,过滤掉没有Tolerations定义的 过滤的过程是这样的:
5)Taint和Toleration的常见使用场景 独占节点 如果想拿出一部分节点,专门给一些特定应用使用,则可以为节点添加这样的Taint: $ kubectl taint nodes nodename dedicated=groupName:NoSchedule 然后给这些应用的Pod加入对应的Toleration。 具有特殊硬件设备的节点 在集群里可能一小部分节点安装了特殊的硬件设备,如GPU芯片,自然会希望把不需要占用这类硬件的Pod排除在外。 可以用下面的命令为节点设置Taint: $ kubectl taint nodes nodename special=true:NoSchedule $ kubectl taint nodes nodename special=true:PreferNoSchedule 然后在Pod中利用对应的Toleration来保障特定的Pod能够使用特定的硬件。 定义Pod驱逐行为,以应对节点故障 在发生故障了的Node上添加一个NoExecute的Taint,正在该节点上运行的Pod将会:
注:在启用了TaintBasedEvictions功能后,为了避免一个网络波动就造成大量Pods被驱逐,尤其是当包含很多本地状态的应用时影响更糟,此时可以为这些Pod增加一个Toleration。类似下面这样: tolerations: - key: "node.alpha./unreachable" operator: "Exists" effect: "NoSchedule" tolerationSeconds: 6000 对于Node未就绪状态,可以把key设置为node.alpha./notReady. 注:如果没有像上面那样为Pod定义"node.alpha./unreachable"或"node.alpha./notReady"的Toleration,那么系统会自动为其加入一个tolerationSeconds=300的默认值,以确保Pod在被驱逐前再运行5min。 9.6 DaemonSet:在每一个Node上调度一个Pod DaemonSet,用于管理在集群中每个Node上只运行一份Pod的副本实例。 常见的使用场景有:
DaemonSet的Pod调度策略与RC类似,除了使用内置的算法在每台Node上进行调度,也可以在Pod的定义中使用NodeSelector或NodeAffinity来指定满足条件的Node范围进行调度。 示例:fluentd-ds.yaml 配置使得在每个节点上都有一个fluentd 容器 因为众所周知的原因,我们不能直接从google下载容器镜像,需要在每个Node节点上像下面这样处理一下。 docker pull docker.io/bigwhite/fluentd-elasticsearch:1.22 docker tag docker.io/bigwhite/fluentd-elasticsearch:1.22 gcr.io/google_containers/fluentd-elasticsearch:1.22 apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: fluentd-cloud-logging namespace: kube-system labels: k8s-app: fluentd-cloud-logging spec: template: metadata: namespace: kube-system labels: k8s-app: fluentd-cloud-logging spec: containers: - name: fluentd-cloud-logging image: gcr.io/google_containers/fluentd-elasticsearch:1.22 resources: limits: cpu: 100m memory: 200Mi env: - name: FLUENTD_ARGS value: -q volumeMounts: - name: varlog mountPath: /var/log readOnly: false - name: containers mountPath: /var/lib/docker/containers volumes: - name: containers hostPath: path: /var/lib/docker/containers - name: varlog hostPath: path: /var/log [root@bogon ~]# kubectl create -f fluentd-ds.yaml daemonset "fluentd-cloud-logging" created [root@bogon ~]# kubectl get ds --namespace=kube-system NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE fluentd-cloud-logging 2 2 2 2 2 <none> 17s [root@bogon ~]# kubectl get pods --namespace=kube-system NAME READY STATUS RESTARTS AGE fluentd-cloud-logging-8rkvk 1/1 Running 0 27s fluentd-cloud-logging-rr45f 1/1 Running 0 27s 9.7 Job:批处理调度 可以通过kubernetes Job资源对象来定义并启动一个批处理任务。批处理任务通常并行(或串行)启动多个计算进程去处理一批工作项(work item),处理完后,整个批处理任务结束。 批处理按任务实现方式不同分为以下几种模式:
Job负责批量处理短暂的一次性任务 (short lived one-off tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。 Kubernetes支持以下几种Job:
根据.spec.completions和.spec.Parallelism的设置,可以将Job划分为以下几种pattern:
Job Spec格式
Job Controller 负责根据Job Spec创建Pod,并持续监控Pod的状态,直至其成功结束。如果失败,则根据restartPolicy(只支持OnFailure和Never,不支持Always)决定是否创建新的Pod再次重试任务。 一个简单的例子: apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: metadata: name: pi spec: containers: - name: pi image: perl command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never $ kubectl create -f ./job.yaml job "pi" created $ pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath={.items..metadata.name}) $ kubectl logs $pods 3.141592653589793238462643383279502... 固定结束次数的Job示例 apiVersion: batch/v1 kind: Job metadata: name: busybox spec: completions: 3 template: metadata: name: busybox spec: containers: - name: busybox image: busybox command: ["echo", "hello"] restartPolicy: Never [root@bogon ~]# kubectl get jobs -o wide NAME DESIRED SUCCESSFUL AGE CONTAINERS IMAGES SELECTOR busybox 3 3 6h busybox busybox:latest controller-uid=cfdb73c4-22fa-11e8-af50-080027cf1a4c pi 1 1 6h pi perl controller-uid=53b4f513-22f8-11e8-af50-080027cf1a4c 9.8 Cronjob:定时任务 CronJob即定时任务,就类似于Linux系统的crontab,在指定的时间周期运行指定的任务。启用该功能需要在API Server中增加一个启动参数–runtime-config=batch/v2alpha1=true CronJob Spec
cronjob.yaml apiVersion: batch/v2alpha1 kind: CronJob metadata: name: hello spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date; echo Hello from the Kubernetes cluster restartPolicy: OnFailure $ kubectl create -f cronjob.yaml cronjob "hello" created 创建和查看cronjob: [root@bogon ~]# kubectl create -f cronjob.yaml cronjob "hello" created [root@bogon kubernetes]# kubectl get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE hello */1 * * * * False 1 Fri, 09 Mar 2018 10:41:00 +0800 在Node节点上查看: [root@localhost ~]# docker ps -a|grep busybox 0754b875faae busybox "/bin/sh -c 'date; e…" 58 seconds ago Exited (0) 58 seconds ago k8s_hello_hello-1520563260-gplkd_default_50810739-2343-11e8-9bfe-080027cf1a4c_0 5dd44ef783af busybox "/bin/sh -c 'date; e…" About a minute ago Exited (0) About a minute ago k8s_hello_hello-1520563200-c6r8v_default_2c97e342-2343-11e8-9bfe-080027cf1a4c_0 39ce93274ccc busybox "/bin/sh -c 'date; e…" 2 minutes ago Exited (0) 2 minutes ago k8s_hello_hello-1520563140-bm5pj_default_08c05c53-2343-11e8-9bfe-080027cf1a4c_0 跟踪查看一下job的执行结果: [root@bogon kubernetes]# kubectl get jobs --watch NAME DESIRED SUCCESSFUL AGE busybox 3 3 8h hello-1520563260 1 1 2m hello-1520563320 1 1 1m hello-1520563380 1 1 45s pi 1 1 8h hello-1520563440 1 0 0s hello-1520563440 1 0 0s hello-1520563440 1 1 7s hello-1520563260 1 1 3m hello-1520563260 1 1 3m hello-1520563260 1 1 3m hello-1520563500 1 0 0s hello-1520563500 1 0 1s hello-1520563500 1 1 7s hello-1520563320 1 1 3m hello-1520563320 1 1 3m hello-1520563320 1 1 3m hello-1520563560 1 0 0s hello-1520563560 1 0 0s hello-1520563560 1 1 8s hello-1520563380 1 1 3m hello-1520563380 1 1 3m hello-1520563380 1 1 3m [root@bogon kubernetes]# kubectl get pods --show-all|grep hello hello-1520563620-nn2fp 0/1 Completed 0 2m hello-1520563680-4xc2f 0/1 Completed 0 1m hello-1520563740-22jbt 0/1 Completed 0 31s 当然,也可以用kubectl run来创建一个CronJob: kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster" $ kubectl get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE hello */1 * * * * False 0 <none> $ kubectl get jobs NAME DESIRED SUCCESSFUL AGE hello-1202039034 1 1 49s $ pods=$(kubectl get pods --selector=job-name=hello-1202039034 --output=jsonpath={.items..metadata.name} -a) $ kubectl logs $pods Mon Aug 29 21:34:09 UTC 2016Hello from the Kubernetes cluster # 注意,删除cronjob的时候不会自动删除job,这些job可以用kubectl delete job来删除 $ kubectl delete cronjob hello cronjob "hello" deleted 9.9 自定义调度器 从k8s v1.6版本开始,增加了Pod的自定义调度器功能。如果Pod中提供了自定义的调度器名称,那么默认的调度器就会忽略该Pod,转由指定的调度器完成Pod的调度。 apiVersion:v1 kind:Pod metadata: name: annotation-second-scheduler labels: name: multischeduler-example spec: schedulerName: my-scheduler containers: - name: pod-with-second-annotation-container image: nginx 可以使用任何语言来实现简单或复杂的自定义调度器。 下面是使用bash脚本进行实现,调度策略为随机选择一个Node。 #!/bin/bash SERVER= 'localhost:8001' while true; do for PODNAME in $(kubectl --server $SERVER get pods -o json | jq '.items[] | select(.spec.schedulerName == "my-scheduler") | select(.spec.nodeName == null) | .metadata.name' | tr -d '"'); do NODES=($(kubectl --server $SERVER get nodes -o json | jq '.items[].metadata.name' | tr -d '"')) NUMNODES=${#NODES[@]} CHOSEN=${NODES[$[ $RANDOM % $NUMNODES ]]} curl --header "Content-Type:application/json" --request POST --data '{"apiVersion":"v1", "kind":"Binding", "metadata":{"name":"'$PODNAME'"}, "target":{"apiVersion":"v1", "kind":"Node", "name":"'$CHOSEN'"}}' echo "Assigned $PODNAME to $CHOSEN" done sleep 1 done
|
|