几个概念:
- Pod:是Kubernetes最基本的部署调度单元,可以包含container,逻辑上表示某种应用的一个实例。比如一个web站点应用由前端、后端及数据库构建而成,这三个组件将运行在各自的容器中,那么我们可以创建包含三个container的pod。
- node: 是 Kubernetes的worker节点,通常也称作为Minion node。除了运行一些kubernetes的组件以外(kubelet, kube-proxy等),还承担着运行容器服务的重任。
- ReplicationController:是pod的复制抽象,用于解决pod的扩容缩容问题。通常,分布式应用为了性能或高可用性的考虑,需要复制多份资源,并且根据负载情况动态伸缩。通过ReplicationController,我们可以指定一个应用需要几份复制,Kubernetes将为每份复制创建一个pod,并且保证实际运行pod数量总是与该复制数量相等(例如,当前某个pod宕机时,自动创建新的pod来替换)
环境介绍:
为了演示kubernetes应用部署策略,准备了7台机器(1个kubernetes master节点和6个kubernetes worker节点),如下图所示。
图片描述
其中:
1) kubernetes master: hchenk8s1(ubuntu 16.04 LTS)
2) etcd: hchenk8s1(可以和kubernetes master不在一个节点上面)
3) worker nodes: hchenk8s2 - hchenk8s7(总共6台机器, 操作系统为ubuntu 16.04 LTS)
完了就开始环境搭建,这里就不演示了,环境搭建部分网上很多。可供参考的比较多。
进入主题
目前,kubernetes提供了3中应用部署策略,下面一一进行介绍:
1. nodeSelector:
nodeSelector是kubernetes提供的最简单的一种应用部署策略,通过一种key=value的方式来部署用户的应用。
从这个参数就能看出来,这种策略的调度对象是node,也就是上面说的kubernetes的worker,说的更明白一点是,用户在创建应用的时候,可以通过nodeSelector来指定某个、或者某组具有某些属性的worker node来创建这些容器服务。这里既然提到了需要根据worker node的某些属性来创建这些容器服务,那就不得不介绍一下worker node的label.
Label: 标签的意思,使用在worker node上面顾名思义就是用来对worker node进行一些标记的。比如说worker node的cpu架构(ppc64, x86, etc)或者分组信息啊什么的。nodeSelector就是通过这些标签来选择应用到底要在哪些机器上去部署。
首先先查看当前kubernetes cluster的worker node的情况。
root@hchenk8s1:~# kubectl get nodes
NAME STATUS AGE
9.111.254.207 Ready,SchedulingDisabled 1d
9.111.254.208 Ready 1d
9.111.254.209 Ready 1d
9.111.254.212 Ready 1d
9.111.254.213 Ready 1d
9.111.254.214 Ready 1d
9.111.254.218 Ready 1d |
从输出可以看到目前测试集群中有6台worker node和一个不可调度的master节点。
下面我们通过nodeSelector来部署应用,并且应用需要部署在指定的机器上面。
在kubernetes集群中,kubelet会上报一些机器属性比如hostname, os, arch等信息记录在nodes的label里面。下面先查看一下这些label.
root@hchenk8s1:~# kubectl get nodes --show-labels
NAME STATUS AGE LABELS
9.111.254.207 Ready,SchedulingDisabled 1d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,kubernetes.io/hostname= 9.111.254.207
9.111.254.208 Ready 1d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,kubernetes.io/hostname= 9.111.254.208
9.111.254.209 Ready 1d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,kubernetes.io/hostname= 9.111.254.209
9.111.254.212 Ready 1d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,kubernetes.io/hostname= 9.111.254.212
9.111.254.213 Ready 1d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,kubernetes.io/hostname= 9.111.254.213
9.111.254.214 Ready 1d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,kubernetes.io/hostname= 9.111.254.214
9.111.254.218 Ready 1d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,kubernetes.io/hostname= 9.111.254.218 |
从输出结果可以看到,每个node都有3个label分别是beta.kubernetes.io/arch,beta.kubernetes.io/os,kubernetes.io/hostname。下面通过hostname作为应用部署的选择策略来部署应用到9.111.254.218机器上面。
以nginx应用为例,准备一个容器应用部署的kubernetes的deployment文件。
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nginx
spec:
replicas: 1
template:
metadata:
labels:
app: nginx
image: nginx_1_8_1
spec:
hostNetwork: false
containers:
- name: nginx
image: nginx:1.8.1
imagePullPolicy: Always
ports:
- protocol: TCP
containerPort: 80
resources:
limits:
cpu: 1000m
memory: 1024Mi
nodeSelector:
kubernetes.io/hostname: 9.111.254.218 |
在yaml文件中加入nodeSelector, 其中key和value分别为label的name和value.
下面就开始见证奇迹了。
通过kubectl创建应用容器服务。
root@hchenk8s1:~# kubectl create -f nginx.yaml
deployment "nginx" created
root@hchenk8s1:~# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 1 1 1 1 9m
root@hchenk8s1:~# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-1245594662-sjjp9 1/1 Running 0 1m 10.1.20.130 9.111.254.218 |
从输出可以看到, nginx的容器服务已经部署到了刚刚指定的机器上面。
当然,nodeSelector自身可以支持多个选择条件,当创建应用的时候,nodeSelector里面的条件都满足的机器会被选择出来用来部署pod.
为了测试nodeSelector多条件支持的测试,我们对6个worker分别进行标记:
root@hchenk8s1:~# kubectl label node 9.111.254.208 storage_type=overlay application_type=web
node "9.111.254.208" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.209 storage_type=overlay application_type=db
node "9.111.254.209" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.212 storage_type=aufs application_type=web
node "9.111.254.212" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.213 storage_type=aufs application_type=db
node "9.111.254.213" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.214 storage_type=devicemapper application_type=web
node "9.111.254.214" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.218 storage_type=devicemapper application_type=db
node "9.111.254.218" labeled |
标记后, 集群结构如下图所示。
下面通过应用部署来测试nodeSelector的多条件选择:
场景1:
创建一个nginx web服务,选择worker node上面,storage_type标记为啊aufs的节点:
期望结果:
nginx web服务部署在节点9.111.254.212上面
步骤:
准备需要创建服务所需要的yaml文件:
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nginx
spec:
replicas: 1
template:
metadata:
labels:
app: nginx
image: nginx_1_8_1
spec:
hostNetwork: false
containers:
- name: nginx
image: nginx:1.8.1
imagePullPolicy: IfNotPresent
ports:
- protocol: TCP
containerPort: 80
resources:
limits:
cpu: 1000m
memory: 1024Mi
nodeSelector:
storage_type: aufs
application_type: web |
从上面的yaml文件可以看到,nodeSelector里面定义了两个条件,分别是storage_type和application_type, 应用只有创建在两个条件同时满足的节点上面。
下面开始创建容器服务。
root@hchenk8s1:~# kubectl create -f nginx.yaml
deployment "nginx" created
root@hchenk8s1:~# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 1 1 1 1 46s
root@hchenk8s1:~# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-2704164239-lr0gj 1/1 Running 0 1m 10.1.58.235 9.111.254.212 |
从输出可以看到,nginx服务已经选择机器9.111.254.212去部署应用。
场景2:
创建一个nginx web服务,选择worker node上面,storage_type标记为啊btrfs的节点:
期望结果:
nginx web选择不到合适的机器部署应用。
步骤:
准备需要创建服务所需要的yaml文件:
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nginx
spec:
replicas: 1
template:
metadata:
labels:
app: nginx
image: nginx_1_8_1
spec:
hostNetwork: false
containers:
- name: nginx
image: nginx:1.8.1
imagePullPolicy: IfNotPresent
ports:
- protocol: TCP
containerPort: 80
resources:
limits:
cpu: 1000m
memory: 1024Mi
nodeSelector:
storage_type: btrfs
application_type: web |
下面开始创建容器服务。
root@hchenk8s1:~# kubectl create -f nginx.yaml
deployment "nginx" created
root@hchenk8s1:~# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 1 1 1 0 58s
root@hchenk8s1:~# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-155862529-m5pr1 0/1 Pending 0 1m <none>
root@hchenk8s1:~# kubectl describe pods nginx-155862529-m5pr1
Name: nginx-155862529-m5pr1
Namespace: default
Node: /
Labels: app=nginx
pod-template-hash=155862529
Status: Pending
IP:
Controllers: ReplicaSet/nginx-155862529
Containers:
nginx:
Image: nginx:latest
Port: 80/TCP
Limits:
cpu: 1
memory: 1Gi
Requests:
cpu: 1
memory: 1Gi
Volume Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-5rj87 (ro)
Environment Variables: <none>
Conditions:
Type Status
PodScheduled False
Volumes:
default-token-5rj87:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-5rj87
QoS Class: Guaranteed
Tolerations: <none>
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 27s 8 {default-scheduler } Warning FailedScheduling pod (nginx-155862529-m5pr1) failed to fit in any node
fit failure summary on nodes : MatchNodeSelector (6) |
从输出可以看到,pod创建失败了,原因是没有找到合适的机器去部署。
总结一下:nodeSelector通过label选择机制,提供了比较简单直观的pod部署策略,从一些方面实现了节点的亲和/反亲和的策略。虽然现在仍然存在在kubernetes中,不过相信这个功能会慢慢被接下来要提到的node Affinity和inter-pod affinity取而代之。
2. NodeAffinity
NodeAffinity是kubernetes 1.2的时候集成进来的,概念上类似于上面介绍的nodeSelector, 通过对node label的选择来部署你的pod的。
先说说nodeAffinity的类型:
目前nodeAffinity支持requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution这两种类型。从字面意思就能看到,类型一的要求要比类型二的苛刻的多,对于类型一来说,更像是上面介绍的nodeSelector的高级版,而对于类型二来说,在创建pod的时候会根据各种调度条件对可调度的机器进行排序,并且不会像类型一那样,因为资源不够或者一些其他原因而创建失败,退而求其次来去选择其他的机器继续创建。
在这两种类型中,ignoredDuringExecution的意思是在node在运行期间如果label发生了变化,之间通过这些类型部署的pod不会因为node label的变化而去重新部署来满足已经定义好的亲和/反亲和的策略。不过社区计划会针对这些case提供requiredDuringSchedulingRequiredDuringExecution的类型来应对因为node label变化,定义的亲和/反亲和的策略发生变化的问题,当然,pod可能就需要重新部署来适应已经发生的变化。
下面设计一个场景还试一下:
场景1:
集群中的6个worker node分别属于3个不同的组,这里分别命名为group1, group2, group3. 需要部署一个nignx应用,并且有4个副本,要求nignx应用部署在除了group3以外的其他group上面。
期望结果:
nginx的应用能部署在group1和group2里的worker node。
步骤:
首先,对集群中的worker node添加label来标识组信息。
root@hchenk8s1:~# kubectl label node 9.111.254.208 group=group1
node "9.111.254.208" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.209 group=group1
node "9.111.254.209" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.212 group=group2
node "9.111.254.212" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.213 group=group2
node "9.111.254.213" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.214 group=group3
node "9.111.254.214" labeled
root@hchenk8s1:~# kubectl label node 9.111.254.218 group=group3
node "9.111.254.218" labeled |
标识完后的worker node信息如下图所示。
下面准备一个用来测试的yaml文件:
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nginx
spec:
replicas: 4
template:
metadata:
labels:
app: nginx
annotations:
scheduler.alpha.kubernetes.io/affinity: >
{
"nodeAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{
"matchExpressions": [
{
"key": "group",
"operator": "In",
"values": ["group1", "group2"]
}
]
}
]
}
}
}
spec:
hostNetwork: false
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- protocol: TCP
containerPort: 80
resources:
limits:
cpu: 500m
memory: 512Mi |
下面开始创建容器服务。
root@hchenk8s1:~# kc create -f nginx_nodeaffinity.yaml
deployment "nginx" created
root@hchenk8s1:~# kc get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-3792017226-5cn0s 1/1 Running 0 1m 10.1.36.194 9.111.254.213
nginx-3792017226-ljq9h 1/1 Running 0 1m 10.1.56.66 9.111.254.208
nginx-3792017226-qfbvs 1/1 Running 0 1m 10.1.64.66 9.111.254.212
nginx-3792017226-tdm23 1/1 Running 0 1m 10.1.183.3 9.111.254.209 |
从测试结果可以看到,4个副本分别部署在了group1和group2上的机器。
上面的例子中用了In的operator,matchExpressions的operator大概有一下几种:
In: 凡是满足values里面条件的机器都会被选择出来。以上面的例子为例,凡是满足group=group1或者group=group2的机器都会被选择出来。
NotIn: 和In相反,凡是满足values里面条件的机器都会被剔除出去。如果以上面的例子为例,operator换成NotIn, 那么group=group1以及group=group2的机器就会被剔除出去,而group=group3的机器则会被选择出来。
Exists: 和In比较类似,凡是有某个标签的机器都会被选择出来。使用Exists的operator的话,values里面就不能写东西了。
DoesNotExist: 和Exists相反,凡是不具备某个标签的机器则会被选择出来。和Exists的Operator一样,values里面也不能写东西了。
Gt: greater than的意思,表示凡是某个value大于设定的值的机器则会被选择出来。
Lt: less than的意思,表示凡是某个value小于设定的值的机器则会被选择出来。
下面2个例子分别看看其他几个operator的使用以及测试结果。
场景2:
集群中的6个worker node,其中的2台标记了network的标签,而其他的4台没有network标签。通过deployment创建一个nginx应用,并且nginx应用有4个副本,通过nodeAffinity选择有network标签的机器进行应用部署。
期望结果:
nginx的应用能部署在有network的标签的机器上面。
步骤:
首先,对集群中的worker node添加label来标识组信息,通过命令可以查看当前集群中的worker node的label信息。
root@hchenk8s1:~# kubectl get nodes --show-labels
NAME STATUS AGE LABELS
9.111.254.208 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group1,kubernetes.io/hostname= 9.111.254.208,network=calico
9.111.254.209 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group1,kubernetes.io/hostname= 9.111.254.209,network=calico
9.111.254.212 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group2,kubernetes.io/hostname= 9.111.254.212
9.111.254.213 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group2,kubernetes.io/hostname= 9.111.254.213
9.111.254.214 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group3,kubernetes.io/hostname= 9.111.254.214
9.111.254.218 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group3,kubernetes.io/hostname= 9.111.254.218 |
准备创建nginx应用的deployment
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nginx
spec:
replicas: 4
template:
metadata:
labels:
app: nginx
annotations:
scheduler.alpha.kubernetes.io/affinity: >
{
"nodeAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{
"matchExpressions": [
{
"key": "network",
"operator": "Exists"
}
]
}
]
}
}
}
spec:
hostNetwork: false
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- protocol: TCP
containerPort: 80
resources:
limits:
cpu: 500m
memory: 512Mi |
从上面的yaml文件可以看到,matchExpression里面定义了nodeAffinity的选择条件,从上面的例子可以看到,nginx应用期望能创建在有network label的机器上。
下面开始创建应用
root@hchenk8s1:~# kubectl create -f nginx_exist.yaml
deployment "nginx" created
root@hchenk8s1:~# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-3031338627-7bbfc 1/1 Running 0 7s 10.1.183.17 9.111.254.209
nginx-3031338627-cd1jz 1/1 Running 0 7s 10.1.56.80 9.111.254.208
nginx-3031338627-wslpb 1/1 Running 0 7s 10.1.183.16 9.111.254.209
nginx-3031338627-zgrxn 1/1 Running 0 7s 10.1.56.79 9.111.254.208 |
从测试结果可以看到,4个副本分别部署在了有network label的机器上面。
场景3:
集群中的6个worker node,其中的2台有kernel-version标签,用来记录机器的内核版本。通过deployment创建一个nginx应用,并且nginx应用有4个副本,通过nodeAffinity选择内核版本范围来进行应用部署。
期望结果:
期望nginx的应用部署在kerver-version大于0320的机器上面。
步骤:
首先为集群中的机器添加lable来标示机器的内核版本信息:
root@hchenk8s1:~# kc get nodes --show-labels -l worker=true
NAME STATUS AGE LABELS
9.111.254.208 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group=group1,kernel-version=0310,kubernetes.io/hostname= 9.111.254.208,worker=true
9.111.254.209 Ready 6d beta.kubernetes.io/arch=amd64, beta.kubernetes.io/os= linux,group=group1,kernel-version=0404,kubernetes.io/hostname= 9.111.254.209,worker=true
9.111.254.212 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group2,kubernetes.io/hostname= 9.111.254.212,worker=true
9.111.254.213 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group2,kubernetes.io/hostname= 9.111.254.213,worker=true
9.111.254.214 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group3,kubernetes.io/hostname= 9.111.254.214,worker=true
9.111.254.218 Ready 6d beta.kubernetes.io/arch= amd64,beta.kubernetes.io/os= linux,group= group3,kubernetes.io/hostname= 9.111.254.218,worker=true |
从上面的输出可以看到,9.111.254.208的kernel-version为0310,9.111.254.209的kernel-version为0404.
下面准备一个nginx的yaml文件,用来创建nginx服务:
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nginx
spec:
replicas: 4
template:
metadata:
labels:
app: nginx
annotations:
scheduler.alpha.kubernetes.io/affinity: >
{
"nodeAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{
"matchExpressions": [
{
"key": "kernel-version",
"operator": "Gt",
"values": ["0320"]
}
]
}
]
}
}
}
spec:
hostNetwork: false
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- protocol: TCP
containerPort: 80
resources:
limits:
cpu: 200m
memory: 256Mi |
上面的文件表示的策略是期望创建服务到kernel-version大于0320的机器上面。
下面开始创建;
root@hchenk8s1:~# kubectl create -f nginx_gt.yaml
deployment "nginx" created
root@hchenk8s1:~# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-4087060041-2x9lw 1/1 Running 0 4s 10.1.183.26 9.111.254.209
nginx-4087060041-4x1dd 1/1 Running 0 4s 10.1.183.23 9.111.254.209
nginx-4087060041-bgt0z 1/1 Running 0 4s 10.1.183.24 9.111.254.209
nginx-4087060041-brgb3 1/1 Running 0 4s 10.1.183.25 9.111.254.209 |
从测试结果可以看到,4个副本都创建在了kernel-version为0404的机器上。
3. Inter-pod affinity/anti-affinity
Inter-pod affinity/anti-affinity是kubernetes 1.4开始支持的,pod的部署策略不再单单的只是通过node label的选择,而是可以从pod层面通过pod的 label来部署自己的应用,简单点说就是你可以通过inter-pod affinity/anti-affinity来决定自己的容器应用亲近或者远离具有某些label的容器应用。
和nodeAffinity一样,inter-pod affinity/anti-affinity也有requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution两种类型,分别表示”hard”和”soft”两种需求。
场景1:
集群中有个db容器服务(mysql),通过使用inter-pod affinity使得数据库上层服务(wordpress)能够和db容器服务在一台机器上。
步骤:
首先准备mysql.yaml文件并且创建容器服务。
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
name: mysql
spec:
containers:
- resources:
limits :
cpu: 0.5
image: mysql:5.6
name: mysql
args:
- "--ignore-db-dir"
- "lost+found"
env:
- name: MYSQL_ROOT_PASSWORD
# change this
value: changeit
ports:
- containerPort: 3306
name: mysql |
下面开始创建:
root@hchenk8s1:~# kubectl create -f mysql.yaml
pod "mysql" created
root@hchenk8s1:~# kc get pods -owide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE LABELS
mysql 1/1 Running 0 8m 10.1.226.66 9.111.254.214 name=mysql |
mysql创建好了,下面开始准备wordpress的yaml文件。
apiVersion: v1
kind: Pod
metadata:
name: wordpress
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: name
operator: In
values:
- mysql
topologyKey: kubernetes.io/hostname
containers:
- image: wordpress:4.7.3-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: 10.1.226.66
- name: WORDPRESS_DB_PASSWORD
value: changeit
ports:
- containerPort: 80
name: wordpress |
yaml文件里面定义了podAffinity, matchExpressions里面指定了需要选择name mysql的pod label来部署wordpress的pod.
下面开始创建:
root@hchenk8s1:~# kubectl create -f wordpress.yaml
pod "wordpress" created
root@hchenk8s1:~# kubectl get pods -owide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE LABELS
mysql 1/1 Running 0 1d 10.1.226.66 9.111.254.214 name=mysql
wordpress 1/1 Running 0 1d 10.1.226.67 9.111.254.214 <none> |
从输出可以看到,wordpress和mysql的pod部署在了一台机器上面,实现了kubernetes.io/hostname上的亲和策略。
场景2.
集群中有个db容器服务(mysql),通过使用inter-pod anti-affinity使得数据库上层服务(wordpress)能够和db容器服务不在一台机器上。
延用上面的mysql的pod, 直接从wordpress的应用开始。
首先还是从yaml文件的准备开始:
apiVersion: v1
kind: Pod
metadata:
name: wordpress
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: name
operator: In
values:
- mysql
topologyKey: kubernetes.io/hostname
containers:
- image: wordpress:4.7.3-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: 10.1.226.66
- name: WORDPRESS_DB_PASSWORD
value: changeit
ports:
- containerPort: 80
name: wordpress |
下面开始创建:
root@hchenk8s1:~# kubectl create -f wordpress.yaml
pod "wordpress" created
root@hchenk8s1:~# kubectl get pods -owide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE LABELS
mysql 1/1 Running 0 1d 10.1.226.66 9.111.254.214 name=mysql
wordpress 1/1 Running 0 4m 10.1.36.207 9.111.254.213 <none> |
从测试结果可以看到,pod分布在了不同的机器上面。
另外,kubernetes的taints和tolerations也是用来对pod进行调度的,这个会在下期进行介绍。 |