华为云用户手册

  • 限制与约束 一个Pod只能绑定一个EIP,一个EIP只能被一个Pod绑定。 创建Pod时,可指定annotation属性,创建完成后,更新EIP相关的annotation均无效。 EIP随Pod创建的优先级高于使用EIPPool创建的EIP。 绑定已有EIP创建的优先级高于EIP随Pod创建的EIP。 绑定EIP的Pod,如果要被公网成功访问,需要添加放通相应公网请求流量的安全组规则。 已经被Pod绑定的弹性公网IP,请勿通过弹性公网IP的console或API直接操作(修改别名/删除/解绑/绑定/转包周期等操作),否则可能导致资源残留。 绑定已有EIP时,使用负载创建的Pod删除重建后,由于需要等待前一个Pod完成解绑,所以重建的Pod就绪时间会变长。 绑定已有的EIP必须是用户手动创建给Pod使用的,不能使用EIPPool生成的EIP,否则会导致EIP状态异常。
  • 生命周期管理 云容器实例基于Kubernetes,提供了容器生命周期钩子,在容器的生命周期的特定阶段执行调用,比如容器在停止前希望执行某项操作,就可以注册相应的钩子函数。目前提供的生命周期钩子函数如下所示。 启动后处理(PostStart):负载启动后触发。 停止前处理(PreStop):负载停止前触发。 调用接口时,只需配置pod的lifecycle.postStart或lifecycle.preStop参数,如下所示。 apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - image: nginx:latest name: container-0 resources: limits: cpu: 500m memory: 1024Mi requests: cpu: 500m memory: 1024Mi lifecycle: postStart: # 启动后处理 exec: command: - "/postStart.sh" preStop: # 停止前处理 exec: command: - "/preStop.sh" imagePullSecrets: - name: imagepull-secret 父主题: Pod
  • 创建静态EIPPool 静态EIPPool,即根据用户指定的多个未使用的EIP,静态纳管底层的EIP资源,同时在CCI命名空间下创建相应的EIP对象。如果EIPPool中的EIP已经被NAT或者ELB使用,则会纳管失败。 以下示例创建了一个名为eippool-demo2的静态EIPPool,并在此EIPPool中纳管10.246.173.254和10.246.172.3两个公网IP。示例如下: apiVersion: crd.yangtse.cni/v1 kind: EIPPool # 创建的对象类别 metadata: # 资源对象的元数据定义 name:eippool-demo2 spec: # EIPPool的配置信息 eips: # 纳管的公网IP - 10.246.173.254 - 10.246.172.3 父主题: 创建EIPPool
  • HTTP GET Readiness Probe的配置与存活探针(livness probe)一样,都是在 Pod Template 的 containers 里面,如下所示,这个Readiness Probe向Pod发送HTTP请求,当Probe收到2xx或3xx返回时,说明Pod已经就绪。 apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx:latest name: container-0 resources: limits: cpu: 500m memory: 1024Mi requests: cpu: 500m memory: 1024Mi readinessProbe: # readinessProbe httpGet: # HTTP GET定义 path: /read port: 80 imagePullSecrets: - name: imagepull-secret
  • Exec Exec方式与HTTP GET方式一致,如下所示,这个探针执行ls /ready命令,如果这个文件存在,则返回0,说明Pod就绪了,否则返回其他状态码。 apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx:latest name: container-0 resources: limits: cpu: 500m memory: 1024Mi requests: cpu: 500m memory: 1024Mi readinessProbe: # Readiness Probe exec: # 定义 ls /ready 命令 command: - ls - /ready imagePullSecrets: - name: imagepull-secret 将上面Deployment的定义保存到deploy-read.yaml文件中,删除之前创建的Deployment,用deploy-read.yaml创建这个Deployment。 # kubectl delete deploy nginx -n $namespace_name deployment.apps "nginx" deleted # kubectl create -f deploy-read.yaml -n $namespace_name deployment.apps/nginx created 这里由于nginx镜像不包含 /ready 这个文件,所以在创建完成后容器不在Ready状态,如下所示,注意READY这一列的值为0/1,表示容器没有Ready。 # kubectl get po -n $namespace_name NAME READY STATUS RESTARTS AGE nginx-7955fd7786-686hp 0/1 Running 0 7s nginx-7955fd7786-9tgwq 0/1 Running 0 7s nginx-7955fd7786-bqsbj 0/1 Running 0 7s 再次查看Service,发现Endpoints一行的值为空,表示没有Endpoints。 $ kubectl describe svc nginx -n $namespace_name Name: nginx ...... Endpoints: ...... 如果此时给容器中创建一个 /ready 的文件,让Readiness Probe成功,则容器会处于Ready状态。再查看Pod和Endpoints,发现创建了/ready文件的容器已经Ready,Endpoints也已经添加。 # kubectl exec -n $namespace_name nginx-7955fd7786-686hp -- touch /ready # kubectl get po -o wide -n $namespace_name NAME READY STATUS RESTARTS AGE IP nginx-7955fd7786-686hp 1/1 Running 0 10m 192.168.93.169 nginx-7955fd7786-9tgwq 0/1 Running 0 10m 192.168.166.130 nginx-7955fd7786-bqsbj 0/1 Running 0 10m 192.168.252.160 # kubectl get endpoints -n $namespace_name NAME ENDPOINTS AGE nginx 192.168.93.169:80 14d
  • Readiness Probe高级配置 与Liveness Probe相同,Readiness Probe也有同样的高级配置选项,上面nginx Pod的describe命令回显有中有如下行。 Readiness: exec [ls /var/ready] delay=0s timeout=1s period=10s #success=1 #failure=3 这一行表示readiness probe的具体参数配置,其含义如下: delay=0s 表示容器启动后立即开始探测,没有延迟时间 timeout=1s 表示容器必须在1s内做出相应反馈给probe,否则视为探测失败 period=10s 表示每10s探测一次 #success=1 表示探测连续1次成功表示成功 #failure=3 表示探测连续3次失败后会重启容器 这些是创建时默认设置的,您也可以手动配置,如下所示。 readinessProbe: # Readiness Probe exec: # 定义 ls /readiness/ready 命令 command: - ls - /readiness/ready initialDelaySeconds: 10 # 容器启动后多久开始探测 timeoutSeconds: 2 # 表示容器必须在2s内做出相应反馈给probe,否则视为探测失败 periodSeconds: 30 # 探测周期,每30s探测一次 successThreshold: 1 # 连续探测1次成功表示成功 failureThreshold: 3 # 连续探测3次失败表示失败
  • Readiness Probe的工作原理 如果调用kubectl describe命令查看Service的信息,您会看到如下信息。 $ kubectl describe svc nginx -n $namespace_name Name: nginx ...... Endpoints: 192.168.113.81:80,192.168.165.64:80,192.168.198.10:80 ...... 可以看到一个Endpoints,Endpoints同样也是Kubernetes的一种资源对象,可以查询得到。 $ kubectl get endpoints -n $namespace_name NAME ENDPOINTS AGE nginx 192.168.113.81:80,192.168.165.64:80,192.168.198.10:80 14m 这里的192.168.113.81:80是Pod的IP:Port,通过如下命令可以查看到Pod的IP,与上面的IP一致。 # kubectl get pods -o wide -n $namespace_name NAME READY STATUS RESTARTS AGE IP nginx-55c54cc5c7-49chn 1/1 Running 0 1m 192.168.198.10 nginx-55c54cc5c7-x87lb 1/1 Running 0 1m 192.168.165.64 nginx-55c54cc5c7-xp4c5 1/1 Running 0 1m 192.168.113.81 通过Endpoints就可以实现Readiness Probe的效果,当Pod还未就绪时,将Pod的IP:Port在Endpoints中删除,Pod就绪后再加入到Endpoints中,如下图所示。 图1 Readiness Probe的实现原理
  • 高级配置 创建Secret Secret是一种加密存储的资源对象,您可以将认证信息、证书、私钥等保存在密钥中,从而解决了密码、token、密钥等敏感数据的配置问题。 如下示例中定义的Secret中包含三条Key-Value。 apiVersion: v1 kind: Secret metadata: name: cert type: Opaque data: ca.crt: ... server.crt: ... server.key: ... 配置tls证书 用户可以通过配置annotation指定exporter server的tls证书套件,进行加密通信,并使用文件挂载的方式,关联证书secret。示例如下: kind: Deployment apiVersion: apps/v1 metadata: name: nginx-tls spec: replicas: 1 selector: matchLabels: app: nginx-tls template: metadata: labels: app: nginx-tls annotations: monitoring.cci.io/enable-pod-metrics: "true" monitoring.cci.io/metrics-port: "19100" monitoring.cci.io/metrics-tls-cert-reference: cert/server.crt monitoring.cci.io/metrics-tls-key-reference: cert/server.key monitoring.cci.io/metrics-tls-ca-reference: cert/ca.crt sandbox-volume.openvessel.io/volume-names: cert spec: volumes: - name: cert secret: secretName: cert defaultMode: 384 containers: - name: container-0 image: 'nginx:alpine' resources: limits: cpu: 1000m memory: 2048Mi requests: cpu: 1000m memory: 2048Mi volumeMounts: - name: cert mountPath: /tmp/secret0 imagePullSecrets: - name: imagepull-secret 表3 tls证书参数说明 Annotation 功能 可选值 默认值 monitoring.cci.io/metrics-tls-cert-reference tls证书volume引用 ${volume-name}/${volume-keyOrPath}(卷/路径) 无(使用http) monitoring.cci.io/metrics-tls-key-reference tls私钥volume引用 ${volume-name}/${volume-keyOrPath} 无(使用http) monitoring.cci.io/metrics-tls-ca-reference tls CA volume引用 ${volume-name}/${volume-keyOrPath} 无(使用http) 以上参数的值为tls的证书、私钥、CA文件所在存储卷的“卷名”和“路径”。
  • 基础配置 以下示例介绍Pod资源监控指标的基础配置方式,提供了Pod级别特性开关和自定义端口的能力。 kind: Deployment apiVersion: apps/v1 metadata: name: nginx-exporter spec: replicas: 1 selector: matchLabels: app: nginx-exporter template: metadata: labels: app: nginx-exporter annotations: monitoring.cci.io/enable-pod-metrics: "true" monitoring.cci.io/metrics-port: "19100" spec: containers: - name: container-0 image: 'nginx:alpine' resources: limits: cpu: 1000m memory: 2048Mi requests: cpu: 1000m memory: 2048Mi imagePullSecrets: - name: imagepull-secret 表2 参数说明 Annotation 功能 可选值 默认值 monitoring.cci.io/enable-pod-metrics 是否开启监控指标特性 true,false(不区分大小写) true monitoring.cci.io/metrics-port 指定pod exporter启动监听端口 合法端口(1~65535) 19100
  • 资源监控指标 资源基础监控包含CPU/内存/磁盘等类别,具体请参见资源监控指标。 表1 资源监控指标 监控指标类 指标名称 释义 CPU container_cpu_system_seconds_total System CPU累积占用时间(单位:秒) container_cpu_usage_seconds_total 容器在所有CPU内核上的累积占用时间 (单位:秒) container_cpu_user_seconds_total User CPU累积占用时间(单位:秒) container_cpu_cfs_periods_total 已经执行的CPU时间周期数 container_cpu_cfs_throttled_periods_total 被限流的CPU时间周期 container_cpu_cfs_throttled_seconds_total 被限流的CPU时间(单位:秒) 文件系统/磁盘IO container_fs_inodes_free 文件系统的可用inode数量 container_fs_usage_bytes 文件系统的使用量(单位:字节) container_fs_inodes_total 文件系统的总计inode数量 container_fs_io_current 磁盘/文件系统当前正在进行的 I/O 数量 container_fs_io_time_seconds_total 磁盘/文件系统花费在 I/O 上的累计秒数 container_fs_io_time_weighted_seconds_total 磁盘/文件系统累积加权 I/O 时间 container_fs_limit_bytes 容器可以使用的磁盘/文件系统总量(单位:字节) container_fs_reads_bytes_total 容器累积读取磁盘/文件系统数据的总量(单位:字节) container_fs_read_seconds_total 容器累积读取磁盘/文件系统数据的秒数 container_fs_reads_merged_total 容器合并读取磁盘/文件系统的累积计数 container_fs_reads_total 容器已完成读取磁盘/文件系统的累积计数 container_fs_sector_reads_total 容器已完成扇区读取磁盘/文件系统的累积计数 container_fs_sector_writes_total 容器已完成扇区写入磁盘/文件系统的累积计数 container_fs_writes_bytes_total 容器累积写入磁盘/文件系统数据的总量(单位:字节) container_fs_write_seconds_total 容器累计写入磁盘/文件系统的秒数 container_fs_writes_merged_total 容器合并写入磁盘/文件系统的累积计数 container_fs_writes_total 容器已完成写入磁盘/文件系统的累积计数 container_blkio_device_usage_total 容器区分IO操作对磁盘的使用总量(单位:字节) 内存 container_memory_failures_total 容器内存分配失败的累积计数 container_memory_failcnt 容器内存使用达到限制的次数 container_memory_cache 容器总页缓存内存(单位:字节) container_memory_mapped_file 容器内存映射文件的大小(单位:字节) container_memory_max_usage_bytes 容器历史最大内存使用量(单位:字节) container_memory_rss 容器常驻内存集的大小(单位:字节) container_memory_swap 容器虚拟内存使用量(单位:字节) container_memory_usage_bytes 容器当前的内存使用量(单位:字节) container_memory_working_set_bytes 容器工作集内存使用量(单位:字节) 网络 container_network_receive_bytes_total 容器网络累积接收数据总量(单位:字节) container_network_receive_errors_total 接收时遇到的错误累积计数 container_network_receive_packets_dropped_total 接收时丢弃的数据包的累积计数 container_network_receive_packets_total 接收数据包的累积计数 container_network_transmit_bytes_total 容器网络累积传输数据总量(单位:字节) container_network_transmit_errors_total 传输时遇到的错误累积计数 container_network_transmit_packets_dropped_total 传输时丢弃的数据包的累积计数 container_network_transmit_packets_total 传输数据包的累积计数 进程 container_processes 容器当前运行的进程数 container_sockets 容器当前打开套接字的个数 container_file_descriptors 容器当前打开文件描述符的个数 container_threads 容器内当前运行的线程数 container_threads_max 容器内允许运行的最大线程数 container_ulimits_soft 容器内1号进程的软 ulimit 值。如果为-1,则无限制,优先级和nice除外 container_spec_cpu_period 容器分配的CPU周期 container_spec_cpu_shares 容器分配的CPU份额 container_spec_memory_limit_bytes 容器可以使用的总内存量限制 container_spec_memory_reservation_limit_bytes 容器可以使用的预留内存限制 container_spec_memory_swap_limit_bytes 容器可以使用的虚拟内存限制 container_start_time_seconds 容器已经运行的时间(单位:秒) container_last_seen 最近一次监控采集器感知到容器的时间 gpu container_accelerator_memory_used_bytes 容器正在使用的GPU加速卡内存量(单位:字节) container_accelerator_memory_total_bytes 总GPU加速卡可用内存量(单位:字节) container_accelerator_duty_cycle GPU加速卡实际运行时间百分比 监控指标数总计59个,与cadvisor提供的指标数一致。 指标详细含义,可参考cadvisor文档:https://github.com/google/cadvisor/blob/v0.39.0/docs/storage/prometheus.md。
  • 在Volume中引用ConfigMap 在Volume中引用ConfigMap,就是通过文件的方式直接将ConfigMap的每条数据填入Volume,每条数据是一个文件,键就是文件名,键值就是文件内容。 如下示例中,创建一个名为vol-configmap的Volume,这个Volume引用名为“configmap-test”的ConfigMap,再将Volume挂载到容器的“/tmp”路径下。Pod创建成功后,在容器的“/tmp”路径下,就有两个文件property_1和property_2,他们的值分别为“Hello”和“World”。 apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - image: nginx:latest name: container-0 resources: limits: cpu: 500m memory: 1024Mi requests: cpu: 500m memory: 1024Mi volumeMounts: - name: vol-configmap # 挂载名为vol-configmap的Volume mountPath: "/tmp1" imagePullSecrets: - name: imagepull-secret volumes: - name: vol-configmap configMap: # 引用ConfigMap name: configmap-test
  • 创建ConfigMap 下面示例创建了一个名为configmap-test的ConfigMap,ConfigMap的配置数据在data字段下定义。 apiVersion: v1 kind: ConfigMap metadata: name: configmap-test data: # 配置数据 property_1: Hello property_2: World
  • 在环境变量中引用ConfigMap ConfigMap最为常见的使用方式就是在环境变量和Volume中引用。 例如下面例子中,引用了configmap-test的property_1,将其作为环境变量EXAMPLE_PROPERTY_1的值,这样容器启动后里面EXAMPLE_PROPERTY_1的值就是property_1的值,即“Hello”。 apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - image: nginx:latest name: container-0 resources: limits: cpu: 500m memory: 1024Mi requests: cpu: 500m memory: 1024Mi env: - name: EXAMPLE_PROPERTY_1 valueFrom: configMapKeyRef: # 引用ConfigMap name: configmap-test key: property_1 imagePullSecrets: - name: imagepull-secret
  • 使用EIPPool 在命名空间下创建完成EIPPool对象后,用户可在Pod模板中添加指定的Annotation: yangtse.io/eip-pool 使用对应EIPPool中的EIP资源,指定后,Pod在创建时将会自动从EIPPool中获取一个可用的EIP并绑定至Pod。 已经被EIPPool使用的EIP,在VPC界面是无法正常的执行绑定、解绑和删除操作的,因此不建议在VPC界面直接操作已被EIPPool使用的EIP。 以创建的eippool-demo1为例。 apiVersion: v1 kind: Pod metadata: annotations: yangtse.io/eip-pool:eippool-demo1 # 通过指定EIPPool的形式使用EIP ... 执行以下命令,查看EIPPool详情,-n表示EIPPool所在的命名空间。 回显信息中名称为eippool-demo1的EIPPool,使用量加1,表示Pod绑定EIP资源成功。 # kubectl get eippool -n $namespace_name NAME EIPS USAGE AGE eippool-demo1 1/3 64m Pod启动后,通过Annotation:yangtse.io/allocated-ipv4-eip可查询到Pod当前使用的EIP。 apiVersion:v1 kind:Pod metadata: annotations: yangtse.io/allocated-ipv4-eip: 116.205.XXX.XXX # Pod被分配到的EIP 如果Pod进行重建,则将会从EIPPool中重新获取一个可用的EIP。 父主题: EIPPool
  • 数组 数组使用连字符和空格“- ”表示,合法的表示方法如下: animal: - Cat - Dog - Goldfish 也可使用行内表示法: animal: [Cat, Dog, Goldfish] 对象和数组可以嵌套使用,形成复合结构: languages: - Ruby - Perl - Python websites: YAML: yaml.org Ruby: ruby-lang.org Python: python.org Perl: use.perl.org
  • 纯量 纯量的数据类型有字符串、布尔值、整数、浮点数、Null、时间、日期。 字符串表示: 字符串默认不使用引号表示: str: This_is_a_line 如果字符串之中包含空格或特殊字符,需要放在引号之中: str: 'content: a string' 单引号和双引号都可以使用,两者区别是单引号可以识别转义字符:双引号不会对特殊字符转义:↵ s1: 'content:\n a string' s2: "content:\n a string" 单引号之中如果还有单引号,必须连续使用两个单引号转义。 str: 'labor''s day' 字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格。 str: This_is a_multi_line 整数表示: int_value: 314 浮点型表示: float_value: 3.14 Null表示: parent: ~ 时间表示: 时间采用ISO8601格式。 iso8601: 2018-12-14t21:59:43.10-05:00 日期表示: 日期采用复合ISO8601格式的年、月、日表示。 date: 1976-07-31
  • LoadBalancer类型的Service 现在您知道可以创建ClusterIP类型的Service,通过Service的IP可以访问到Service后端的Pod。 云容器实例同时还支持创建LoadBalancer类型的Service,将增强型ELB实例与Service绑定,这样访问ELB实例的流量就会访问到Service。 ELB实例根据IP地址不同可以分为私网ELB实例和公网ELB实例,区别在于公网ELB实例绑定了一个公网IP,您可以根据需要选择。您可以调用创建负载均衡器(增强型)创建ELB实例,更方便的方法是通过ELB控制台创建增强型ELB实例。 ELB实例必须与Service在同一个VPC内,否则无法绑定。 跨namespace不支持service或ELB 域名 访问,只能通过ELB内网IP:端口访问。 图3 LoadBalancer Service 下面是一个创建LoadBalancer类型的Service。创建完成后,可以通过ELB的IP:Port访问到后端Pod。 apiVersion: v1 kind: Service metadata: name: nginx annotations: kubernetes.io/elb.id: 77e6246c-a091-xxxx-xxxx-789baa571280 # ELB的ID spec: selector: app: nginx ports: - name: service0 targetPort: 80 port: 8080 # ELB访问端口 protocol: TCP type: LoadBalancer # Service的类型
  • 直接访问Pod的问题 负载创建完成后,如何访问负载呢?访问负载实际上就是访问Pod,但是直接访问Pod会有如下几个问题: Pod会随时被Deployment这样的控制器删除重建,那访问Pod的结果就会变得不可预知。 Pod的IP地址是在Pod启动后才被分配,在启动前并不知道Pod的IP地址。 应用往往都是由多个运行相同镜像的一组Pod组成,一个个Pod的访问也变得不现实。 举个例子,假设有这样一个应用程序,使用Deployment创建了前台和后台,前台会调用后台做一些计算处理,如图1所示。后台运行了3个Pod,这些Pod是相互独立且可被替换的,当Pod出现状况被重建时,新建的Pod的IP地址是新IP,前台的Pod无法直接感知。 图1 负载间访问
  • Service是如何工作的 Kubernetes中的Service对象就是用来解决上述Pod访问问题的。Service有一个固定IP地址,Service将访问他的流量转发给Pod,具体转发给哪些Pod通过Label来选择,而且Service可以给这些Pod做负载均衡。 那么对于上面的例子,通过为前后台添加两个Service,通过Service来访问Pod,这样前台Pod就无需感知后台Pod的变化,如图2所示。 图2 通过Service访问Pod
  • 约束与限制 一个Pod只能绑定一个EIP。 绑定EIP的Pod,如果要被公网成功访问,需要添加放通相应公网请求流量的安全组规则。 EIPPool正在被Pod使用时,不支持直接删除EIPPool,需删除关联Pod,再删除EIPPool。 EIPPool为namespace级别资源,不可跨namespace使用。 工作负载滚动升级时,默认策略是逐步创建新Pod然后删除旧Pod(请参见升级策略),则可能会由于EIPPool中EIP数量不足而升级失败。建议:EIPPool池的大小略大于使用该EIPPool的所有的Deployment副本数之和,或者maxSurge配置为0,可支持工作负载先减后增滚动升级。
  • 更新EIPPool 考虑到用户实际场景,EIPPool对象当前只允许用户调整EIP的数量,即对EIPPool进行扩缩容。用户如果需要调整EIP其他参数,可新建EIPPool对象后在负载配置中替换即可。 EIPPool缩容时,如果EIP资源被占用,则不会删除对应的EIP,直到占用解除。 以动态创建的eippool-demo1为例,将amount:3改为amount: 5。 apiVersion: crd.yangtse.cni/v1 kind: EIPPool metadata: name: eippool-demo1 namespace: xxx spec: amount: 5 # EIP资源池中的EIP数量 eipAttributes: # EIP的一些属性 ... 执行以下命令,查看EIPPool详情,-n表示EIPPool所在的命名空间。 回显信息中名称为eippool-demo1的EIPPool,USAGE由0/3更新为0/5,表示EIPPool更新成功。 # kubectl get eippool -n $namespace_name NAME EIPS USAGE AGE eippool-demo1 0/5 39m
  • Deployment如何控制Pod 继续查询Pod,如下所示。 $ kubectl get pods -n $namespace_name NAME READY STATUS RESTARTS AGE nginx-7f98958cdf-tdmqk 1/1 Running 0 13s nginx-7f98958cdf-txckx 1/1 Running 0 13s 如果删掉一个Pod,您会发现立马会有一个新的Pod被创建出来,如下所示,这就是前面所说的Deployment会确保有2个Pod在运行,如果删掉一个,Deployment会重新创建一个,如果某个Pod崩溃或有什么问题,Deployment会自动拉起这个Pod。 $ kubectl delete pod nginx-7f98958cdf-txckx -n $namespace_name $ kubectl get pods -n $namespace_name NAME READY STATUS RESTARTS AGE nginx-7f98958cdf-tdmqk 1/1 Running 0 21s nginx-7f98958cdf-tesqr 1/1 Running 0 21s 看到有如下两个名为nginx-7f98958cdf-tdmqk和nginx-7f98958cdf-tesqr的Pod, 其中nginx是直接使用Deployment的名称,-7f98958cdf-tdmqk和-7f98958cdf-tesqr是kubernetes随机生成的后缀。 您也许会发现这两个后缀中前面一部分是相同的,都是7f98958cdf,这是因为Deployment不是直接控制Pod的,Deployment是通过一种名为ReplicaSet的控制器控制Pod,通过如下命令可以查询ReplicaSet,其中rs是ReplicaSet的缩写。 $ kubectl get rs -n $namespace_name NAME DESIRED CURRENT READY AGE nginx-7f98958cdf 3 3 3 1m 这个ReplicaSet的名称为nginx-7f98958cdf,后缀-7f98958cdf也是随机生成的。 Deployment控制Pod的方式如图1所示,Deployment控制ReplicaSet,ReplicaSet控制Pod。 图1 Deployment通过ReplicaSet控制Pod 如果使用kubectl describe命令查看Deployment的详情,您就可以看到ReplicaSet,如下所示,可以看到有一行 NewReplicaSet: nginx-7f98958cdf (2/2 replicas created),而且 Events 里面事件确是把ReplicaSet的实例扩容到2个。在实际使用中您也许不会直接操作ReplicaSet,但了解Deployment通过控制ReplicaSet来控制Pod会有助于您定位问题。 $ kubectl describe deploy nginx -n $namespace_name Name: nginx Namespace: default CreationTimestamp: Sun, 16 Dec 2018 19:21:58 +0800 Labels: app=nginx ... NewReplicaSet: nginx-7f98958cdf (2/2 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 5m deployment-controller Scaled up replica set nginx-7f98958cdf to 2
  • 升级 在实际应用中,升级是一个常见的场景,Deployment能够很方便的支撑应用升级。 Deployment 可以设置不同的升级策略,有如下两种。 RollingUpdate:也就是滚动升级(逐步创建新Pod然后删除旧Pod),也是默认策略 Recreate:也就是先把当前Pod删掉再重新创建Pod Deployment的升级可以是声明式的,也就是说只需要修改Deployment的YAML定义即可,比如使用kubectl edit命令将上面Deployment中的镜像修改为nginx:alpine。修改完成后再查询ReplicaSet和Pod,发现创建了一个新的ReplicaSet,Pod也重新创建了。 $ kubectl edit deploy nginx -n $namespace_name $ kubectl get rs -n $namespace_name NAME DESIRED CURRENT READY AGE nginx-6f9f58dffd 2 2 2 1m nginx-7f98958cdf 0 0 0 48m $ kubectl get pods -n $namespace_name NAME READY STATUS RESTARTS AGE nginx-6f9f58dffd-tdmqk 1/1 Running 0 21s nginx-6f9f58dffd-tesqr 1/1 Running 0 21s Deployment可以通过maxSurge 和 maxUnavailable两个参数控制升级过程中同时重新创建Pod的比例,这在很多时候是非常有用,配置如下所示。 spec: strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 type: RollingUpdate maxSurge:与Deployment中spec.replicas相比,可以有多少个Pod存在,默认值是25%,比如spec.replicas为 4,那升级过程中就不能超过5个 Pod存在,即按1个的步伐升级,实际升级过程中会换算成数字,且换算会向上取整。这个值也可以直接设置成数字。 maxUnavailable:与Deployment中spec.replicas相比,可以有多少个Pod失效,也就是删除的比例,默认值是25%,比如spec.replicas为 4,那升级过程中就至少有3个Pod存在,即删除Pod 的步伐是 1。同样这个值也可以设置成数字。 在前面的例子中,由于spec.replicas是2,如果maxSurge和maxUnavailable都为默认值25%,那实际升级过程中,maxSurge允许最多3个 Pod 存在(向上取整,2*1.25=2.5,取整为3),而 maxUnavailable 则不允许有 Pod Unavailable(向上取整,2*0.75=1.5,取整为2),也就是说在升级过程中,一直会有2个Pod处于运行状态,每次新建一个Pod,等这个Pod创建成功后再删掉一个旧Pod,直至Pod全部为新Pod。
  • 回滚 回滚也称为回退,即当发现升级出现问题时,让应用回到老的版本。Deployment可以非常方便的回滚到老版本。 例如上面升级的新版镜像有问题,可以执行kubectl rollout undo命令进行回滚。 $ kubectl rollout undo deployment nginx -n $namespace_name deployment "nginx" rolled back Deployment之所以能如此容易的做到回滚,是因为Deployment是通过ReplicaSet控制Pod的,升级后之前ReplicaSet都一直存在,Deployment回滚做的就是使用之前的ReplicaSet再次把Pod创建出来。Deployment中保存ReplicaSet的数量可以使用revisionHistoryLimit参数限制,默认值为10。
  • 创建Deployment 以下示例为创建一个名为nginx的Deployment负载,使用nginx:latest镜像创建两个Pod,每个Pod占用500m core CPU、1G内存。 apiVersion: apps/v1 # 注意这里与Pod的区别,Deployment是apps/v1而不是v1 kind: Deployment # 资源类型为Deployment metadata: name: nginx # Deployment的名称 spec: replicas: 2 # Pod的数量,Deployment会确保一直有2个Pod运行 selector: # Label Selector matchLabels: app: nginx template: # Pod的定义,用于创建Pod,也称为Pod template metadata: labels: app: nginx spec: volumes: - name: cci-sfs-test # sfs卷的名称 persistentVolumeClaim: claimName: cci-sfs-test containers: - image: nginx:latest name: container-0 resources: limits: cpu: 500m memory: 1024Mi requests: cpu: 500m memory: 1024Mi volumeMounts: - name: cci-sfs-test mountPath: /tmp/sfs0/krlp2k8j # sfs卷的容器内挂载路径 imagePullSecrets: # 拉取镜像使用的证书,必须为imagepull-secret - name: imagepull-secret 从这个定义中可以看到Deployment的名称为nginx,spec.replicas定义了Pod的数量,即这个Deployment控制2个Pod;spec.selector是Label Selector(标签选择器),表示这个Deployment会选择Label为app=nginx的Pod;spec.template是Pod的定义,内容与Pod中的定义完全一致。 将上面Deployment的定义保存到deployment.yaml文件中,使用kubectl创建这个Deployment。 使用kubectl get查看Deployment和Pod,可以看到DESIRED值为2,这表示这个Deployment期望有2个Pod,CURRENT也为2,这表示当前有2个Pod,AVAILABLE为2表示有2个Pod是可用的。 $ kubectl create -f deployment.yaml -n $namespace_name $ kubectl get deployment -n $namespace_name NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 2 2 2 2 8s
  • 环境变量 环境变量是容器运行环境中设定的一个变量。 环境变量为应用提供极大的灵活性,您可以在应用程序中使用环境变量,在创建容器时为环境变量赋值,容器运行时读取环境变量的值,从而做到灵活的配置,而不是每次都重新编写应用程序制作镜像。 另外,您还可以使用ConfigMap和Secret作为环境变量,详细信息请参见使用ConfigMap和Secret提高配置灵活性。 环境变量的使用方法如下所示,配置spec.containers.env字段即可。 apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - image: nginx:1 name: container-0 resources: limits: cpu: 500m memory: 1024Mi requests: cpu: 500m memory: 1024Mi env: # 环境变量 - name: env_key value: env_value - name: pod_name valueFrom: # 引用Pod的名称 fieldRef: fieldPath: metadata.name - name: pod_ip valueFrom: # 引用Pod的IP地址 fieldRef: fieldPath: status.podIP imagePullSecrets: - name: imagepull-secret 父主题: Pod
  • 配置有效的Liveness Probe liveness probe应该检查什么 一个好的liveness probe应该检查应用内部所有关键部分是否健康,并使用一个专有的URL访问,例如 /health,当访问 /health 时执行这个功能,然后返回对应结果。这里要注意不能做鉴权,不然 probe 就会一直失败导致陷入重启的死循环。 另外检查只能限制在应用内部,不能检查依赖外部的部分,例如当前端web server不能连接数据库时,这个就不能看成web server不健康。 liveness probe必须轻量 liveness probe不能占用过多的资源,且不能占用过长的时间,否则所有资源都在做健康检查,这就没有意义了。例如Java应用,就最好用HTTP GET方式,如果用 Exec 方式,JVM启动就占用了非常多的资源。
  • HTTP GET HTTP GET方式是最常见的探测方法,其具体机制是向容器发送HTTP GET请求,如果probe收到2xx或3xx,说明容器是健康的,定义方法如下所示。 apiVersion: v1 kind: Pod metadata: name: liveness-http spec: containers: - name: liveness image: k8s.gcr.io/liveness args: - /server livenessProbe: # liveness probe httpGet: # HTTP GET定义 path: /healthz port: 8080 创建这个Pod。 $ kubectl create -f liveness-http.yaml -n $namespace_name pod/liveness-http created 如上,这个probe往容器的8080端口发送HTTP GET请求,上面的程序会在第五次请求会返回500状态码,这时Kubernetes会去重启容器。 查看Pod详情。 $ kubectl describe po liveness-http -n $namespace_name Name: liveness-http ...... Containers: container-0: ...... State: Running Started: Mon, 12 Nov 2018 22:57:28 +0800 Last State: Terminated Reason: Error Exit Code: 137 Started: Mon, 12 Nov 2018 22:55:40 +0800 Finished: Mon, 12 Nov 2018 22:57:27 +0800 Ready: True Restart Count: 1 Liveness: http-get http://:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m5s default-scheduler Successfully assigned default/pod-liveness to node2 Normal Pulling 74s (x2 over 3m4s) kubelet, node2 pulling image "pod-liveness" Normal Killing 74s kubelet, node2 Killing container with id docker://container-0:Container failed liveness probe.. Container will be killed and recreated. 可以看到Pod当前状态是Running,Last State是Terminated,Restart Count为1,说明已经重启1次,另外从事件中也可以看到 Killing container with id docker://container-0:Container failed liveness probe.. Container will be killed and recreated. 另外,容器Kill后会重新创建一个新容器,不只是之前的容器重启。
  • Exec Exec即执行具体命令,具体机制是probe执行容器中的命令并检查命令退出的状态码,如果状态码为0则说明健康,定义方法如下所示。 apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-exec spec: containers: - name: liveness image: busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 livenessProbe: # liveness probe exec: # Exec定义 command: - cat - /tmp/healthy 上面定义在容器中执行cat /tmp/healthy命令,如果成功执行并返回0,则说明容器是健康的。
  • Liveness Probe高级配置 上面liveness-http的describe命令回显中有如下行。 Liveness: http-get http://:8080/ delay=0s timeout=1s period=10s #success=1 #failure=3 这一行表示liveness probe的具体参数配置,其含义如下: delay=0s 表示容器启动后立即开始探测,没有延迟时间 timeout=1s 表示容器必须在1s内做出相应反馈给probe,否则视为探测失败 period=10s 表示每10s探测一次 #success=1 表示探测连续1次成功表示成功 #failure=3 表示探测连续3次失败后会重启容器 这些是创建时默认设置的,您也可以手动配置,如下所示。 apiVersion: v1 kind: Pod metadata: name: liveness-http spec: containers: - image: k8s.gcr.io/liveness livenessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 10 # 容器启动后多久开始探测 timeoutSeconds: 2 # 表示容器必须在2s内做出相应反馈给probe,否则视为探测失败 periodSeconds: 30 # 探测周期,每30s探测一次 successThreshold: 1 # 连续探测1次成功表示成功 failureThreshold: 3 # 连续探测3次失败表示失败 initialDelaySeconds一般要设置大于0,这是由于很多情况下容器虽然启动成功,但应用就绪也需要一定的时间,需要等就绪时间之后才能返回成功,否则就会导致probe经常失败。 另外failureThreshold可以设置多次循环探测,这样在实际应用中健康检查的程序就不需要多次循环,这一点在开发应用时需要注意。
共100000条