Kubernetes中Pod对象学习笔记

 

Pod,是k8s项目里面最小的API对象,项目原子调度单位

 
容器的本质是进程
k8s就是操作系统!
将“进程组”的概念映射到容器技术中,应用之间的密切的协作关系,使得必须部署在同一台机器上。
k8s项目的调度器统一按照Pod而非容器的资源需求进行计算的。
 
意义:容器设计模式。
 

Pod的实现原理

1.逻辑概念:宿主机上一组共享资源的容器,Pod里面的所有容器,共享一个Network Namespace,并且可以声明共享同一个Volume。
2.Pod实现需要使用一个中间容器,叫做Infra容器,永远是第一个被创建,其他用户定义的容器,通过Join Network Namespace,与Infra关联。
 
 
A和B网络互通,都可以使用localhost访问,和Infra看到的完全一样
一个Pod只有一个ip地址;
其他的网络资源,都是一个Pod一份,所有容器共享
Pod的声明周期只跟Infra容器一致。
 
如果要给K8S开发一个网络插件,重点考虑这个Pod 的Network Namespace ,而不是每个用户容器如何使用你的网络配置。
考虑:一个容器跑多个功能不相关的应用,优先考虑是不是更应该描述为一个Pod里的多个容器。
 
例子一:WAR包和Web服务器。
 
单纯用Docker 方式来做
方法一:War包放在Tomcat的webapps下,做成一个镜像。如果要更新WAR包内容,重新制作一个新的发布镜像;
方法二:不管WAR包,永远只发布一个Tomcat容器,webapps目录,必须声明一个hostPath类型的Volume,把宿主机的War包挂载在Tomcat运行。
 
K8S的解决方式,Pod,可以把WAR包和Tomcat分别做成镜像,然后作为一个Pod里的两个容器组合,方式如下:
 
apiVersion: v1
kind: Pod
metadata:
  name: javaweb-2
spec:
  initContainers:
  - image: geektime/sample:v2
    name: war
    command: ["cp", "/sample.war", "/app"]
    volumeMounts:
    - mountPath: /app
      name: app-volume
  containers:
  - image: geektime/tomcat:7.0
    name: tomcat
    command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
    volumeMounts:
    - mountPath: /root/apache-tomcat-7.0.42-v2/webapps
      name: app-volume
    ports:
    - containerPort: 8080
      hostPort: 8001
  volumes:
  - name: app-volume
    emptyDir: {}

 

 
两个容器,WAR包容器是一个Init Container容器,比spec.containers定义的容器先启动,
 
/app 挂载了一个名叫app-volume的Volume
Tomcat容器,同样声明了挂载app-volume到自己的webapps目录下。
所以当Tomcat容器启动时,webapps就存在这个sample.war了。
 
sidecar。在一个Pod中,启动一个辅助容器,来完成一些独立于主进程(主容器)外的工作。
 
实例二:容器的日志收集。
 
把日志文件输出到容器的/var/log目录
可以把一个Pod的Volume挂载到应用容器的/var/log
在Pod同时运行一个sidecar容器,声明一个挂载同一个Volume到自己的/var/log
 
sidecar的主要工作,使用共享的Volume来完成文件的操作。
 
Pod的另外一个特性,是所有容器共用一个Network Namespace.
典型例子:Istio这个微服务治理项目。
 
 
总结
Pod,实际上是扮演传统基础设施里“虚拟机”的角色,而容器,则是这个虚拟机里运行的用户程序。
 
 
 
 
 

Pod属性

 
问题:哪些属性属于Pod对象,而哪些又属于Container
 
凡是调度,网络,存储,以及安全相关的属性,基本都是Pod级别。
 
共同特征,属于“机器”这个整体,而不是里面运行的“程序”。网卡,防火墙
 
NodeSelector:提供用户将Pod与Node进行绑定的字段,
 
apiVersion: v1
kind: Pod
...
spec:
nodeSelector:
   disktype: ssd

 

NodeName:k8s认为这个Pod已经经过了调度,调度的结果就是赋值的节点名字。
HostAliases:定义Pod的hosts文件内容
apiVersion: v1
kind: Pod
...
spec:
  hostAliases:
  - ip: "10.1.2.3"
    hostnames:
    - "foo.remote"
    - "bar.remote"
...

 

凡是跟容器的Linux Namespace相关的属性,也一定是Pod级别。
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  shareProcessNamespace: true
  containers:
  - name: nginx
    image: nginx
  - name: shell
    image: busybox
    stdin: true
    tty: true

 

凡是Pod中的容器共享宿主机的Namespace,也是Pod级别。
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  hostNetwork: true
  hostIPC: true
  hostPID: true
  containers:
  - name: nginx
    image: nginx
  - name: shell
    image: busybox
    stdin: true
    tty: true

 

Kubernetes项目中对Container的定义,和Docker相比并没有什么太大区别。我在前面 的容器技术概念入门系列文章中,和你分享的Image (镜像)、Command (启动命 令)、workingDir (容器的工作目录)、Ports (容器要开发的端口),以及 volumeMounts (容器要挂载的Volume )都是构成Kubernetes项目中Container的主 要字段。不过在这里,还有这么几个属性值得你额外关注。
1. ImagePullPolicy字段。镜像拉取的策略
默认值:Always,每次创建Pod都要重新拉取一次镜像。另外,当镜像是nginx:last,也会是Always。
当定义为Nerver或者IfNotPresent时。不会主动去拉取。
2. Lifecycle:Container Lifecycle Hooks,容器状态发生变化时触发一系列“钩子”。
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
      preStop:
        exec:
          command: ["/usr/sbin/nginx","-s","quit"]

 

Pod 生命周期的变化,主要体现在 Pod API 对象的 Status 部分,这是它除了 Metadata 和 Spec 之外的第三个重要字段
pod.status.phase,就是 Pod 的当前状态,它有如下几种可能的情况
  • Pending:这个 Pod 里有些容器因为某种原因而不能被顺利创建;
  • Running:Pod 已经调度成功,跟一个具体的节点绑定
  • Succeeded:Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
  • Unknown。异常状态,主从节点通信出问题。

Pod使用进阶

特殊的Volume,叫做Projected Volume (投射数据卷),为容器提供预先定义好的数据。

四种特殊的Volume

  • Secret; Pod访问的加密数据,存放到Etcd中,通过Pod容器的挂载Volume,访问这些Secret保存的信息。
  • ConfigMap;
  • Downward API;
  • ServiceAccountToken。
 
 

Secret使用场景

数据库Credential信息。
apiVersion: v1
kind: Pod
metadata:
  name: test-projected-volume
spec:
  containers:
  - name: test-secret-volume
    image: busybox
    args:
    - sleep
    - "86400"
    volumeMounts:
    - name: mysql-cred
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: mysql-cred
    projected:
      sources:
      - secret:
          name: user
      - secret:
          name: pass

 

$ cat ./username.txt

admin
$ cat ./password.txt
c1oudc0w!
$ kubectl create secret generic user --from-file=./username.txt
$ kubectl create secret generic pass --from-file=./password.txt

 

查看Secret对象
 $ kubectl get secrets

 

也可以直接编写YAML文件的方式创建这个Secret对象,
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  user: YWRtaW4=
  pass: MWYyZDFlMmU2N2Rm

 

Secret 对象要求这些数据必须是经过 Base64 转码的
$ echo -n 'admin' | base64
YWRtaW4=
$ echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm

#解码输出
echo -n "str" | base64 -d

 

注意:生产环境要使用Secret加密插件的内容
 
创建pod
$ kubectl create -f test-projected-volume.yaml

当 Pod 变成 Running 状态之后,我们再验证一下这些 Secret 对象是不是已经在容器里了:
$ kubectl exec -it test-projected-volume -- /bin/sh
$ ls /projected-volume/
user
pass
$ cat /projected-volume/user
root
$ cat /projected-volume/pass
1f2d1e2e67df

 

发起数据连接代码写好重试和超时的逻辑。
 
ConfigMap
 
不需加密,应用的配置信息
 
可以使用 kubectl create configmap 从文件或者目录创建 ConfigMap,也可以直接编写 ConfigMap 对象的 YAML 文件。
# .properties文件的内容
$ cat example/ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
# 从.properties文件创建ConfigMap
$ kubectl create configmap ui-config --from-file=example/ui.properties
# 查看这个ConfigMap里保存的信息(data)
$ kubectl get configmaps ui-config -o yaml
apiVersion: v1
data:
  ui.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true
    how.nice.to.look=fairlyNice
kind: ConfigMap
metadata:
  name: ui-config
  ...

 

kubectl get -o yaml 这样的参数,会将指定的 Pod API 对象以 YAML 的方式展示出来
 
Downward API
让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息
apiVersion: v1
kind: Pod
metadata:
  name: test-downwardapi-volume
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
spec:
  containers:
    - name: client-container
      image: k8s.gcr.io/busybox
      command: ["sh", "-c"]
      args:
      - while true; do
          if [[ -e /etc/podinfo/labels ]]; then
            echo -en '\n\n'; cat /etc/podinfo/labels; fi;
          sleep 5;
        done;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
          readOnly: false
  volumes:
    - name: podinfo
      projected:
        sources:
        - downwardAPI:
            items:
              - path: "labels"
                fieldRef:
                  fieldPath: metadata.labels

 

暴露Pod的metadata.labels信息给容器。
$ kubectl create -f dapi-volume.yaml
$ kubectl logs test-downwardapi-volume
cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"

 

字段丰富,可以具体使用查看文档
 
1. 使用fieldRef可以声明使用:
spec.nodeName - 宿主机名字
status.hostIP - 宿主机IP
metadata.name - Pod的名字
metadata.namespace - Pod的Namespace
status.podIP - Pod的IP
spec.serviceAccountName - Pod的Service Account的名字
metadata.uid - Pod的UID
metadata.labels['<KEY>'] - 指定<KEY>的Label值
metadata.annotations['<KEY>'] - 指定<KEY>的Annotation值
metadata.labels - Pod的所有Label
metadata.annotations - Pod的所有Annotation
2. 使用 resourceFieldRef可以声明使用:
容器的CPU limit
容器的CPU request
容器的memory limit
容器的memory request
 
Secret、ConfigMap,以及 Downward API 这三种 Projected Volume 定义的信息,大多还可以通过环境变量的方式出现在容器里
 
Service Account
 
API server 授权
作用:Kubernetes 系统内置的一种“服务账户”,它是 Kubernetes 进行权限分配的对象
 
授权信息和文件,保存在特殊的Secret对象里,叫做ServiceAccountToken,任何运行在 Kubernetes 集群上的应用,都必须使用这个 ServiceAccountToken 里保存的授权信息,也就是 Token,才可以合法地访问 API Server
 
默认“服务账户”(default Service Account),无需挂载,
任意一个运行在k8s的集群里面的Pod,每一个Pod,都已经自动声明一个类型为Secret,名称为default-token-xxxx 的 Volume
 
 
容器健康检查和恢复机制
 
定义一个健康检查“探针”(Probe),kubelet根据Probe决定容器的状态。 livenessProbe
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: test-liveness-exec
spec:
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

 

exec,执行命令,容器启动后5秒开始执行。每5秒执行一次
restartPolicy k8s标准字段,默认值是Always,任何时候发生异常都一定会被重新创建。
Pod 的恢复过程,永远都是发生在当前节点上
Pod与node绑定后,不会离开这个节点,即使宕机,。如果需要出现在其他的节点,需要使用Deployment来管理,
 
restartPolicy值可以是Nerver ,OnFailure.实际情况,合理设置恢复策略。
 
可以定义为发起HTTP,或者TCP请求。格式如下:
...
livenessProbe:
     httpGet:
       path: /healthz
       port: 8080
       httpHeaders:
       - name: X-Custom-Header
         value: Awesome
       initialDelaySeconds: 3
       periodSeconds: 3
    ...
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

 

Pod 其实可以暴露一个健康检查 URL(比如 /healthz),或者直接让健康检查去检测应用的监听端口
k8s自动给Pod填充某些字段。
PodPreset(Pod 预设置)
cat preset.yaml
apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: allow-database
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: "6379"
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

 

selector  后面追加的定义一定是是带有role: frontend标签的Pod对象。
 
$ kubectl create -f preset.yaml
$ kubectl create -f pod.yaml

 

这时,Pod 运行起来之后,我们查看一下这个 Pod 的 API 对象:
$ kubectl get pod website -o yaml
apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
  annotations:
    podpreset.admission.kubernetes.io/podpreset-allow-database: "resource version"
spec:
  containers:
    - name: website
      image: nginx
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
      ports:
        - containerPort: 80
      env:
        - name: DB_PORT
          value: "6379"
  volumes:
    - name: cache-volume
      emptyDir: {}

 

PodPreset 里定义的内容,只会在 Pod API 对象被创建之前追加在这个对象本身上,而不会影响任何 Pod 的控制器的定义。
Deployment 对象本身是永远不会被 PodPreset 改变的,被修改的只是这个 Deployment 创建出来的所有 Pod
定义多个PodPreset,k8s会合并两个有修改的,如果有冲突,就不修改
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值