kubernetes 概念

基础对象

文档: https://v1-13.docs.kubernetes.io/docs/concepts/

对象 说明
Pod k8s最小单位
Service 网络、自动发现
Volume 存储
Namespace 命名空间

基于基础对象抽象出以下Controllers

对象 说明
ReplicaSet
Deployment 无状态服务
StatefulSet 有状态服务
jobs

Kubernetes Components

master

对象 说明
kube-apiserver 暴露Kubernetes api
etcd etcd 用来存储所有的集群数据
kube-scheduler 调度pods
kube-controller-manager 控制Controller
cloud-controller-manager

Node

对象 说明
kubelet 保证容器跑在pod里 并且保证pod的健康,kubelet只管理用Kubernetes创建的容器。
kube-proxy 网络和连接转发
Container Runtime

Addons(插件)

Client Libraries:自己写代码调用Kubernetes API

yaml写法
yaml spec pod
yaml spec deployment
labels
annotations

Namespaces

使用场景: 多团队或者多项目 ,如果只是为了区分服务,使用 labels就可以了。区分开发、测试、预发布、正式环境
通过Resource Quotas分配集群资源
创建和删除namespaces

#查看命名空间
kubectl get namespaces

#设置命名空间
kubectl --namespace=<insert-namespace-name-here> run nginx --image=nginx
kubectl --namespace=<insert-namespace-name-here> get pods

#设置默认使用哪个命名空间
kubectl config set-context $(kubectl config current-context) --namespace=<insert-namespace-name-here>

创建Service的时候会创建对应的dns, dns的入口是..svc.cluster.local,这表示dns只解析本的命名空间请求,这在使用命名空间区分测试、预发布、正式环境很有用。如果你需要跨命名空间访问则需要域名。

并不是所有的Kubernetes 资源都在同一个命名空间里,可以使用以下的命令查看

#在namespace里的资源
kubectl api-resources --namespaced=true

#不在namespace里的资源
kubectl api-resources --namespaced=false

Labels and Selectors

Labels 对object而言的key是唯一的。
一个合理的key应该由前缀和名称组成,使用/分隔。
名称不超过63个字符,可以使用- _ .分隔
前缀是可选的,如果指定了不超过253个字符 并且以/结尾
value不超过63个字符,不要有除- _ .外的特殊字符。
labels搜索

操作 说明 示例
= 等于 environment=production
== 等于 environment==production
!= 不等于 environment!=production
in in environment in (production, qa)
notin notin tier notin (frontend, backend)
exists exists只检测key有没有存在 partition
noexists exists只检测key有没有存在 !partition
多个合并操作environment=production,tier!=frontend
#查询environment=production&&tier=frontend
kubectl get pods -l environment=production,tier=frontend
kubectl get pods -l 'environment in (production),tier in (frontend)'

#查询key是environment && environment值不是frontend
kubectl get pods -l 'environment,environment notin (frontend)'

#matchExpressions,key、operator、values ,operator支持In、NotIn、Exists、DoesNotExist
selector:
  matchLabels:
    component: redis
  matchExpressions:
    - {key: tier, operator: In, values: [cache]}
    - {key: environment, operator: NotIn, values: [dev]}

node selection

Annotations

Labels 用来搜索object和object集合,相反 Annotations用来注释让其他工具或者类库可以检索到metadata。

#annotations可以包含labels中不允许的字符
"metadata": {
  "annotations": {
    "key1" : "value1",
    "key2" : "value2"
  }
}

Field Selectors

使用resource字段值查询Kubernetes resource 比如:
metadata.name=my-service
metadata.namespace!=default
status.phase=Pending

#使用--field-selector查询pod为Running状态
kubectl get pods --field-selector status.phase=Running

支持的fields因不同的资源类型而不通,所有的资源类型都支持metadata.name和metadata.namespace
但其他的fields就不一定,如果遇到不支持的fields会报错。
操作符支持=、==和!=

kubectl get services --field-selector metadata.namespace!=default

链式操作

kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always

同时搜索多资源

kubectl get statefulsets,services --field-selector metadata.namespace!=default

推荐做法
有状态服务

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/name: mysql #名称
    app.kubernetes.io/instance: wordpress-abcxzy #唯一名称,标识应用程序
    app.kubernetes.io/version: "5.7.21" #版本
    app.kubernetes.io/component: database  #架构中的组件
    app.kubernetes.io/part-of: wordpress #哪个程序的一部分
    app.kubernetes.io/managed-by: helm #用什么工具管理

无状态服务labels例子:

#Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: myservice
    app.kubernetes.io/instance: myservice-abcxzy
...

#Service
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: myservice
    app.kubernetes.io/instance: myservice-abcxzy
...
#注意同一个服务里的 Deployment和Service里的labels是一样

包含数据库的web应用

#Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: wordpress
    app.kubernetes.io/instance: wordpress-abcxzy
    app.kubernetes.io/version: "4.9.4"
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/component: server
    app.kubernetes.io/part-of: wordpress
...

#Service
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: wordpress
    app.kubernetes.io/instance: wordpress-abcxzy
    app.kubernetes.io/version: "4.9.4"
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/component: server
    app.kubernetes.io/part-of: wordpress
...

#Mysql StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/name: mysql
    app.kubernetes.io/instance: wordpress-abcxzy
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/component: database
    app.kubernetes.io/part-of: wordpress
    app.kubernetes.io/version: "5.7.21"
...

#Mysql Service
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: mysql
    app.kubernetes.io/instance: wordpress-abcxzy
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/component: database
    app.kubernetes.io/part-of: wordpress
    app.kubernetes.io/version: "5.7.21"
...

Kubernetes Object Management对象管理

管理技巧
Warning: Kubernetes 对象有多种管理技巧,不要混用。

命令行管理

#创建Deployment 对象
kubectl run nginx --image nginx
kubectl create deployment nginx --image nginx

#创建Deployment 
kubectl run

#创建Service 对象
kubectl expose

#创建一个可自动扩缩容的controller,比如Deployment
kubectl autoscale

#指定子命令
create <objecttype> [<subtype>] <instancename>
kubectl create service nodeport <myservicename>

#查看帮助
kubectl create service nodeport -h

#水平扩容
kubectl  scale

#添加或者删除注释
kubectl annotate

#添加或者删除label
kubectl label

#设置object里的字段
kubectl set <field>

#直接用编辑器打开配置修改
kubectl edit

#使用patch来修改object 
kubectl patch

#使用set命令在创建objects 之前修改内容
#kubectl create service -o yaml --dry-run 这个命令不会发送给Kubernetes  而是输出YAML 内容到标准输出,通过管道发送给下一个命令
#kubectl set selector --local -f - -o yaml 从管道接收配置然后写入到YAML 
#kubectl create -f - 执行创建命令
kubectl create service clusterip my-svc --clusterip="None" -o yaml --dry-run | kubectl set selector --local -f - 'environment=qa' -o yaml | kubectl create -f -

#使用--edit在创建前修改objects 
kubectl create service clusterip my-svc --clusterip="None" -o yaml --dry-run > /tmp/srv.yaml
kubectl create --edit -f /tmp/srv.yaml

Imperative object configuration命令式对象配置

#创建objects 
kubectl create -f <filename|url>
kubectl create -f nginx.yaml

#更新objects 
kubectl replace -f <filename|url>
kubectl replace -f nginx.yaml

replace局限性:
1.从一个配置文件里创建一个object 
2.用其他方式修改object 里的某些字段
3.再修改第1步的配置文件然后使用replace 执行,这样第2步修改的内容就会丢失。
所以要注意不要用多种方式管理同一个object 。如果你想用多个文件管理同一个object要使用kubectl apply来管理。


#删除objects 
kubectl delete -f <filename|url>
kubectl delete -f nginx.yaml -f redis.yaml
kubectl delete <type>/<name>
kubectl delete deployment/nginx

#查看objects , -o yaml 输出完整的object 配置,使用kubectl get  -h查看详细内容
kubectl get -f <filename|url> -o yaml

#查看pod的输出或者错误
kubectl  logs

#修改object 但不保存在配置文件里
kubectl create -f <url> --edit

#从命令行管理转成配置管理 imperative object configuration
#1.导出object配置到本地文件
kubectl get <kind>/<name> -o yaml --export > <kind>_<name>.yaml

#2从导出的配置文件中删除status 字段

#3使用replace更新
kubectl replace -f <kind>_<name>.yaml

定义controller selectors和PodTemplate labels
警告:强烈建议不要修改controller的selectors,推荐的方法是使用PodTemplate

selector:
  matchLabels:
      controller-selector: "extensions/v1beta1/deployment/nginx"
template:
  metadata:
    labels:
      controller-selector: "extensions/v1beta1/deployment/nginx"

Declarative object configuration声明式对象配置

#创建objects
kubectl apply -f <directory>/

#simple_deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80


#查看变动,类似 git diff
kubectl diff -f simple_deployment.yaml

#执行变动
kubectl apply -f simple_deployment.yaml

#打印配置信息
kubectl get -f simple_deployment.yaml -o yaml


#递归查看变动
kubectl diff -R -f configs/

#递归执行变动
kubectl apply -R -f configs/

#使用kubectl scale扩容
kubectl scale deployment/nginx-deployment --replicas=2

#删除objects
#推荐使用imperative command 去删除objects
kubectl delete -f <filename>

#prune 还处于alpha阶段,后续版本可能会修改,并且该命令是查询label来删除的~ 所以可能删除其他东西
kubectl apply -f <directory/> --prune -l <labels>

#查看object配置
kubectl get -f <filename|url> -o yaml

kubectl apply 如何计算差异并合并修改内容

Nodes

Node Status包含以下信息

对象 包含内容
Addresses HostName, 可以使用kubelet --hostname-override修改
ExternalIP:集群外IP
InternalIP:集群内IP
Condition OutOfDisk:添加新pod空间不足为True,否则为False
Ready:node 正常为True,node不健康为False,node控制器没有接收到node-monitor-grace-period为Unknown,默认接收间隔时间40S
MemoryPressure node内存不足为True,否则为False
PIDPressurenode进程太多True,否则为False
DiskPressure 磁盘大小不足为True,否则为False
NetworkUnavailable 网络配置不正确为True,否则为False
node状态为Unknown或者False时间超过pod-eviction-timeout设定的时间(默认5分钟),出问题的node上的所有pod会被删除。 在某些情况下,node因为网络问题 unreachable,apiserver 无法和kubelet 通讯, 删除pod命令在恢复通讯后发送。
在Kubernetes 1.5版本以前node controller 会强制删除unreachable 的pod,在1.5 版本以后不会强制删除。
Capacity 描述node上的可用资源: CPU,内存以及可以在节点上调度的最大pod数
Info node的一般信息比如内核版本、Kubernetes 版本、Docker版本、OS 名称。由Kubelet从node收集。

管理node
Kubernetes本身不创建node,他通过外部提供者创建,比如本地物理机、虚拟机、谷歌云等。所以Kubernetes创建node的时候其实是创建一个object 来表示node。一旦创建成功,Kubernetes会检查node是否有效。比如如果你用下面的内容创建node:

{
  "kind": "Node",
  "apiVersion": "v1",
  "metadata": {
    "name": "10.240.79.157",
    "labels": {
      "name": "my-first-k8s-node"
    }
  }
}

Kubernetes创建一个内部node对象,并且通过metadata.name检查node是否健康。如果node有效,所有的服务都会执行。否则集群会忽略它直到node变成有效。Kubernetes 会不断的检查无效的node对象。你必须删除node才能停止检查。
node controller、 kubelet和 kubectl 三个组件和Kubernetes node接口交互。

Node Controller
node controller是Kubernetes的主要组件,管理node的各方面。
node controller 在node的生命周期里扮演多个角色。
1.注册的时候为node 分配CIDR 块(如果CIDR 开启)。
2.node controller云服务商的可用集群列表最新的内部节点列表。当在node跑在云环境中,每当node unhealthy, node controller 会请求云服务商 那个node的VM 是否依旧可用。如果不可用,node controller 会从node列表里把这个node删除。
3.监控nodes的健康。当一个node变成unreachable时 node controller负责把NodeStatus 从NodeReady 变成ConditionUnknown 。如果node在--node-monitor-period 设置的秒数中一直处于ConditionUnknown,那么五分钟后会开始终止该node下的pods。
Kubernetes 1.13版本之前,node的心跳是NodeStatus。1.13版本开始node lease 做为alpha被引入。如果开启了node lease 每个节点会定期更新kube-node-lease namespace 的 Lease,然后NodeStatus 和 node lease 都会被当成node的心跳。Node leases 会经常更新,但是只有NodeStatus有变更或者超过设定的报告时间时(默认1分钟) 才会从node报告给master 。node lease 比NodeStatus轻量,并且让心跳在可扩展性和性能上的代价更小。
在 Kubernetes 1.4,我们更新了 node controller 的逻辑,当大量node节点到master出问题的时候能更好的处理。从1.4开始node controller 在决定剔除一个pod 的时候会先查看集群里的所有node的状态。
大多数情况下,node controller 通过--node-eviction-rate(默认0.1) 参数来限制驱除率,pods 驱除效率不会超过10秒/1node 。
当node在给定的可用区域里变成unhealthy的时候 node驱逐行为会发生变化,同时node controller也会检查区域里的node的unhealthy 百分比。如果node unhealthy 数小于--unhealthy-zone-threshold (默认0.55)驱逐率就会开始减小:如果集群node数小于--large-cluster-size-threshold(默认50),驱逐将会停止,否则驱逐率会降到--secondary-node-eviction-rate(默认0.01)) 每秒。以上的方案会在每个可用的分区里生效的原因是,可用区域可能会从master上分区,而其他的还保留连接。如果你的集群没有跨多服务商的可用区域,那么只会有一个可用区域。
让你node跨可用区域的主要原因是当一个区域不可用的时候可以通过workload 转移到健康的区域。因此当区域里所有node的都unhealthy,node controller会以正常的--node-eviction-rate 驱逐节点。当集群里所有node都unhealthy,node controller假设master的连接出现问题,会停止所有的驱逐直到连接恢复。
从Kubernetes 1.6开始,如果pods 不允许有NoExecute,NodeController 还负责驱逐node中有NoExecute状态的pods,另外作为一个alpha 特性,这个功能默认是关闭的,NodeController 负责添加taints 到相应的问题node ,比如node unreachable 或 not ready。NoExecute详细信息可以查看https://v1-13.docs.kubernetes.io/docs/concepts/configuration/taint-and-toleration/

node自注册
kubelet 带参数--register-node=true(默认情况下),kubelet会尝试使用API server 自注册。
对于自注册,kubelet 还带有以下参数。

对象 说明
--kubeconfig 验证node的证书路径
--cloud-provider 告知云提供商如何读取metadata
--register-node 使用API server 自动注册
--register-with-taints 用给定的taints注册节点,如果register-node是false 这个操作不会执行。
--node-ip nodeIP地址
--node-labels 点击查看
--node-status-update-frequency 指定kubelet 发送node status 到master的频率。

当Node authorization mode 和NodeRestriction admission plugin 被启用。kubelets只会修改他自己节点的资源。

手动管理node
kubelet 参数--register-node=false 开启手动创建node。
不管--register-node怎么设置,管理员都可以修改node里的资源。包括设置labels和让node变得不可调度。
node的Labels 和 pods 上的node selectors 可以结合起来控制调度,比如控制一个pod只能在某些node上执行。
控制一个node不接受新的pod调度请求,并且不影响任何已经在该node上的pod,这在重启node之前的准备是很有用的。

#pod变得不可调度
kubectl cordon $NODENAME

node上DaemonSet类型的pods会绕过Kubernetes 的调度器 并且不会遵守不可调度属性。这假设daemons是机器上的即使它耗尽资源要重启。

Node capacity
node容量是node对象的一部分。通常 ,node在创建的时候会注册自己并且报告容量。如果你使用手动管理,就必须在添加node的时候设置node容量。
Kubernetes 调度器确保node上的所有pod有足够的资源。它会检查node上的所有容器加起来不会超过node的容量。包含所有用kubelet启动的容器。但是不包含执行容器(docker、cri等占用的容量) 或所有在容器外的进程。
如果你想明确的为非pod进程保留资源,查看
node api

Master-Node communication

这个文档记录master和Kubernetes 集群的通讯方式。允许用户可以自定义加强网络,这样集群就可以跑在不信任的网络上,或者公网IP上。
Cluster to Master
从集群到master的所有通讯方式都在apiserver终止。在一个典型的deployment,apiserver用来监听客户端的HTTPS 远程连接。 如果允许匿名请求或者 service account tokens ,那么 authorization必须启用。
Nodes必须提供一个公共根证书这样他们就可以使用有效的客户端凭证来安全的连接apiserver 。比如在一个默认的GKE deployment,提供给kubelet的客户端凭证采用客户端证书的形式。查看自动配置kubelet 证书
pods希望能借助service account来安全的连接到apiserver,这样Kubernetes 将会自动注入公共的根证书并且当它实例化的时候有一个有效的bearer token 给pod 。kubernetes service 配置一个虚拟IP地址来转发到apiserver的HTTPS端(通过 kube-proxy转发)。
master组件还通过安全端口与群集通信。
从集群到master连接操作模式默认是安全的,并且可以在不可信网络或者公网上执行。

Master to Cluster
master到集群的通讯主要有两种
1.apiserver 到集群上的每个node上的kubelet 进程。
2.apiserver 通过apiserver的proxy 到任何node、pod、或者service。
apiserver to kubelet
从apiserver到kubelet的连接用于:
1.从pod接收日志
2.附加到执行的pod
3.提供kubelet的端口转发功能
这些连接在kubelet的HTTPS端终止。默认情况下apiserver 不会检查kubelet的服务证书,这样这些连接会遭到中间人攻击(中间人攻击是一种功网络攻击方式),在不可信任或者公网上会不安全。
要校验这次连接,使用--kubelet-certificate-authority参数 提供给apiserver 一个根证书来验证kubelet的证书。
如果无法使用--kubelet-certificate-authority, 用 SSH tunneling来在不可信或者公网上通信apiserver 和kubelet 。
最后Kubelet authentication and/or authorization并且启用才能安全的使用 kubelet API。

apiserver to nodes, pods, and services
apiserver 到nodes, pods, 和 services 默认是通过HTTP连接,因此既未经过身份验证也未加密。可以在连接前面加上https:前缀来安全的链接,但是在HTTPS 端没有验证证书的提供方也没有提供客户端凭证来加密连接,也没有提供完整性保证。这些请求在不可信网络和公网上目前还不安全。

SSH Tunnels
Kubernetes 支持SSH隧道来保护master->集群的通信方式。在这种配置中,apiserver 同步发起SSH 隧道到集群里的每个node并且通过隧道传递 kubelet, node, pod, or service的所有流量。隧道可确保流量不会在node的网络外部暴露。
SSH隧道已经被弃用了,不应该使用它。替代方案还在设计中。

Concepts Underlying the Cloud Controller Manager

Images

Updating Images
更新镜像默认是IfNotPresent ,如果镜像在本地已经存在就会跳过更新。如果要强制更新可以使用下面的方法:
1.imagePullPolicy设置成 Always
2.忽略imagePullPolicy,对要更新的镜像使用 :latest tag
3.忽略imagePullPolicy,对要更新的镜像加上tag
4.启用AlwaysPullImages功能

Building Multi-architecture Images with Manifests
Docker CLI 现在支持在docker manifest (create|push|annotate) 。这些命令现在可以用来build 和push manifests。你可以用docker manifest inspect 来查看manifest。docker文档查看
以上的命令完全依赖Docker CLI。你需要编辑$HOME/.docker/config.json 设置experimental成enabled 或者你可以在使用docker CLI命令的时候设置DOCKER_CLI_EXPERIMENTAL 环境变量为enabled。
请使用Docker 18.06以上的版本,低于这个版本 要嘛有bug 要嘛不支持这个特性。
如果你上传manifests出现问题,只要把$HOME/.docker/manifests 清空就可以刷新了。
对于Kubernetes 我们使用镜像会带上-$(ARCH)后缀。为了兼容,对旧的镜像请生成带后缀的. 好的做法对有manifest的是生成带pause,对需要向后兼容的生成带pause-amd64。
使用私有仓库可能需要秘钥才能读取镜像。私有仓库
Docker把秘钥存储在$HOME/.dockercfg或者$HOME/.docker/config.json文件里。如果你把秘钥文件放在以下的路径,kubelet 在pull 镜像的时候也会使用。

{--root-dir:-/var/lib/kubelet}/config.json

{cwd of kubelet}/config.json

${HOME}/.docker/config.json

/.docker/config.json

{--root-dir:-/var/lib/kubelet}/.dockercfg

{cwd of kubelet}/.dockercfg

${HOME}/.dockercfg

/.dockercfg

这里有一些推荐步骤来配置你的私有仓库。

  1. docker login [server] 会在$HOME/.docker/config.json里存储登录信息
  2. 查看$HOME/.docker/config.json 看是不是你需要的
    3.获取node列表

nodes=$(kubectl get nodes -o jsonpath='{range.items[*].metadata}{.name} {end}')
nodes=$(kubectl get nodes -o jsonpath='{range .items[*].status.addresses[?(@.type=="ExternalIP")]}{.address} {end}')
4.把你本地的.docker/config.json复制到其他机器for n in $nodes; do scp ~/.docker/config.json [email protected]$n:/var/lib/kubelet/config.json; done
创建一个pod来验证配置对不对:

kubectl create -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: private-image-test-1
spec:
  containers:
    - name: uses-private-image
      image: $PRIVATE_IMAGE_NAME
      imagePullPolicy: Always
      command: [ "echo", "SUCCESS" ]
EOF
pod/private-image-test-1 created

使用kubectl logs private-image-test-1kubectl describe pods/private-image-test-1 | grep "Failed" 来看pod是否创建成功。
你必须保证所有节点都有相同的.docker/config.json 不然有些节点的pod会成功 有些节点的pod会失败。如果你使用node自动扩容,那么每个实例模板都需要包含.docker/config.json 或者挂载一个包含该文件的驱动器。
私有秘钥一加入 .docker/config.json所有pod有访问私有仓库的权限。

Pre-pulling Images 预加载镜像
在Google Kubernetes Engine环境下在每个节点下 会有一个.dockercfg文件凭证来访问google容器仓库。你就不用使用这种方法管理。
如果你可以控制node配置,那么适合使用这种方法。这种方法不能在GCE或者任何会自动更换node的提供商环境。
默认情况下,kubelet 会尝试从指定的仓库pull镜像。但是如果imagePullPolicy设置成IfNotPresentNever,那么就会优先使用本地镜像。
如果你想使用预加载的镜像,你必须保证集群里的所有node 都有相同的镜像。

Specifying ImagePullSecrets on a Pod pod上指定ImagePullSecrets

kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
secret/myregistrykey created.

如果你是以秘钥文件形式来跑以上命令 可以查看Create a Secret based on existing Docker credentials.这在同时使用多个私有仓库的时候很有用。如果你用的是kubectl create secret docker-registry 那么只会使用单个仓库。
pod拉取镜像只对本命令空间有效,如果其他namespace也要这样执行命令才能拉取对应的镜像。
例子:

apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: awesomeapps
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: myregistrykey

查看在 serviceAccount 如何设置imagePullSecrets 字段.更详细的信息查看 Add ImagePullSecrets to a Service Account
可以和.docker/config.json结合使用。
配置私有镜像有多种方案,以下是建议的方案:

  1. 集群只跑开源镜像。不必隐藏镜像。

    只使用Docker hub 上的镜像,不必做任何配置。
  2. 集群跑一些私有镜像对公司外部隐藏,但是对集群使用者不隐藏。

    2.1 使用私有托管<a href="https://docs.docker.com/registry/"> Docker registry</a>、阿里云dockerhub 等。然后在` .docker/config.json `的每个node做手动配置。
    2.2 或者使用自己搭建的私有仓库
    2.3 在谷歌的Kubernetes 云服务上使用 Google Container Registry 。
    2.4 使用imagePullSecrets
  3. 集群上使用私有镜像,但是对某些重要镜像进行更严格的权限控制。

    3.1 确保<a href="https://v1-13.docs.kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages">AlwaysPullImages admission controller </a>开启。否则所有的pod可能都有所有镜像的访问权限。
    3.2 把敏感信息保存成Secret资源 而不是直接打包在镜像里。
  4. 一个多用户集群的每个用户需要有自己的私有仓库

    4.1  确保<a href="https://v1-13.docs.kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages">AlwaysPullImages admission controller </a>开启。否则所有的pod可能都有所有镜像的访问权限。
    4.2 私有仓库开启需要验证。
    4.3 每个用户生成私有仓库访问凭证,保存在secret资源,放入每个用户的namespace里。
    4.4 每个用户 使用imagePullSecrets

    如果你需要访问多个仓库,你可以为每个仓库创建一个或多个secret 。Kubelet 会把所有的imagePullSecrets合并到一个虚拟的.docker/config.json 文件里

Container Environment Variables 容器环境变量

Kubernetes Container environment 为容器提供了一些重要的资源

  1. 文件系统 volumes和镜像的组合。
  2. 容器自己的信息
  3. 集群里其他objects 的信息

Container information 容器信息
hostname 容器里pod的hostname
Pod名称和namespace 通过downward API变成可用的环境变量
用户在pod里自定义的变量 在容器里也是可用的 ,和 Docker 镜像里的静态变量一样。

Cluster information 集群信息
当容器创建的时候所有service的列表可以用做容器的环境变量,这些变量和Docker links的语法一样。

FOO_SERVICE_HOST=<the host the service is running on>
FOO_SERVICE_PORT=<the port the service is running on>

Runtime Class

RuntimeClass 是一个alpha 特性,用来选择容器运行时的配置。

Container Lifecycle Hooks 容器生命周期 hook

Containers有两个hook:

  1. PostStart 容器创建后执行。
  2. PreStop 容器通过API 终止之前 或者在 活动探测失败,抢占,资源争用等 事件之前执行。如果容器已经终止或者处于事情完成状态去调用PreStop hook 会失败。PreStop 是同步阻塞的,所以在容器删除之前肯定会执行完成。该hook没有参数。

Hook handler implementations hook实现
实现hook有两种方法:

  1. Exec 在cgroups和容器命名空间中 执行一个指定的脚本 比如 pre-stop.sh。命令消耗的资源由容器计算。
  2. HTTP HTTP请求

Hook handler execution hook执行
Hook 会在pod容器的上下文同步执行。 对于 PostStart hook 容器ENTRYPOINT 和hook 是异步激活的。如果hook任务执行花太久时间容器就读不到running 状态
对于PreStop 如果hook 在执行期间挂起,那么Pod 的状态就会是Terminating 并且会在terminationGracePeriodSeconds之后kill。
所以使用hook处理器的时候需要尽可能轻量。但是在有些情况下长时间的任务是有意义的 比如在停止Container之前保存状态。

Hook delivery guarantees hook调用保证
hook有可能会有多次调用。所以实现hook的时候要注意。
HTTPhook只进行单次调用执行, 如果hook接收器或者网络出问题不会重复发送调用。
但是如果kubelet 在重启的过程当中发送hook,那么kubelet 重启完后还会再发送一次hook。

Debugging Hook handlers debug hook
Pod事件日志中是没有Hook 的。如果hook处理失败 会广播一个事件:
PostStart: 广播FailedPostStartHook事件
PreStop :广播 FailedPreStopHook事件
使用 kubectl describe pod <pod_name> 就能看到这些事件了

Pod Overview

Pods 有两种使用方法

  1. pod单个容器运行。 每个pod一个容器是Kubernetes 最常用的方式。这种方式下 Kubernetes 是直接管理pod
  2. pod多个容器协同运行。Pod将这些容器和存储资源作为单个可管理实体包装在一起
    The Distributed System Toolkit: Patterns for Composite Containers

Container Design Patterns
每个pod执行单个应用实例。如果要扩容应用,你要使用多个pod,每个应用一个pod。Kubernetes里这种pod通常指replication。Replicated pod的创建和管理抽象成 Controller。

pod管理多个容器
pod管理的多个容器,这些容器都在同一台的物理机或者虚拟机里。这些容器可以共享资源、相互依赖、互相通讯,协同如何停止运行。
pod管理多个容器是比较新的功能,你应该只有在容器是紧耦合的情况下才使用它。
比如你有一个容器 是共享volume文件web应用,并且有一个单独的容器从远程更新这些文件。
QQ_20190418180327

pod对组成他的容器提供两个资源共享方式:Networking(网络)和storage(存储)。
Networking
每个pod会分配一个唯一的IP。Pod 里的每个容器共享网络namespace,包括IP地址、网络端口。Pod 里的容器是通过localhost互相访问的。当pod里的容器和pod外的容器通讯的时候,他们必须协调如何使用共享网络资源。

Storage
pod可以指定一组共享的存储volumes。所有pod里的容器都可以访问这个共享volumes 来共享数据。

Working with Pods
你很少会直接创建单个pod,这是因为pod被设计成 短暂的 一次性的。当创建pod的时候,pod被调度在node上跑,pod就保存在该node上直到进程结束。当node资源不够 或者node失效了,pod会被删除。
重启容器不要与重启pod混淆概念了,pod本身是不会运行的,它提供了容器的持续运行环境,直到被删除为止。
pod不能自我修复。如果pod调度给一个node失败,或者调度自己的操作失败,pod会被删除。pod资源不足或者node处于维护状态的时候会被删除。管理pod实例的操作叫做Controller。虽然pod可以直接使用,但是在Kubernetes 中 用Controller管理pod是更普遍的做法。查看Pods and Controllers来看 Kubernetes 如何使用Controllers来扩容和复原pod。

Pods and Controllers你可以用Controller 创建和管理多个pod,也可以在集群里复制、回滚、自动恢复pod。