1. 初步尝试 k8s
kubectl run
命令是最简单的部署引用的方式,它自动创建必要组件,这样,我们就先不必深入了解每个组件的结构
2. k8s基本概念
-
pod容器
:docker容器的封装对象,一个pod可以封闭多个docker容器,k8s以pod为单位来部署容器 -
rc控制器(ReplicationController)
:RC是用来自动控制Pod部署的工具,它可以自动启停Pod,对Pod进行自动伸缩. -
service
:提供一个不变的访问地址,可以向所有容器转发调用
3. 使用 rc 和 pod 部署应用
cd ~/
k run \
--image=luksa/kubia \
--port=8080 \
--generator=run/v1 kubia
k get rc
---------------------------------------
NAME DESIRED CURRENT READY AGE
kubia 1 1 1 57s
k get pods
----------------------------------------------
NAME READY STATUS RESTARTS AGE
kubia-h2xtp 1/1 Running 0 70s
4. 使用 service 对外暴露 pod
k expose \
rc kubia \
--type=NodePort \
--name kubia-http
k get svc
这里创建了一个 service 组件,用来对外暴露pod访问,在所有节点服务器上,暴露了20916端口,通过此端口,可以访问指定pod的8080端口
5. pod自动伸缩
k8s对应用部署节点的自动伸缩能力非常强,只需要指定需要运行多少个pod,k8s就可以完成pod的自动伸缩
# 将pod数量增加到3个
k scale rc kubia --replicas=3
k get po -o wide
# 将pod数量减少到1个
k scale rc kubia --replicas=1
# k8s会自动停止两个pod,最终pod列表中会只有一个pod
k get po -o wide
6. pod
6.1 创建kubia-manual.yml部署文件
cat <<EOF > kubia-manual.yml
apiVersion: v1 # k8s api版本
kind: Pod # 该部署文件用来创建pod资源
metadata:
name: kubia-manual # pod名称前缀,后面会追加随机字符串
spec:
containers: # 对pod中容器的配置
- image: luksa/kubia # 镜像名
imagePullPolicy: Never
name: kubia # 容器名
ports:
- containerPort: 8080 # 容器暴露的端口
protocol: TCP
EOF
6.2 使用部署文件创建pod
k create -f kubia-manual.yml
k get po
6.3 查看pod的部署文件
# 查看pod的部署文件
k get po kubia-manual -o yaml
6.4 查看pod日志
k logs kubia-manual
6.5 pod端口转发
使用 kubectl port-forward 命令设置端口转发,对外暴露pod.
使用服务器的 8888 端口,映射到 pod 的 8080 端口
k port-forward kubia-manual --address localhost,192.168.64.191 8888:8080
# 或在所有网卡上暴露8888端口
k port-forward kubia-manual --address 0.0.0.0 8888:8080
6.6 pod标签
6.6.1 创建pod时指定标签
通过kubia-manual-with-labels.yml
部署文件部署pod
在部署文件中为pod设置了两个自定义标签:creation_method
和env
cat <<EOF > kubia-manual-with-labels.yml
apiVersion: v1 # api版本
kind: Pod # 部署的资源类型
metadata:
name: kubia-manual-v2 # pod名
labels: # 标签设置,键值对形式
creation_method: manual
env: prod
spec:
containers: # 容器设置
- image: luksa/kubia # 镜像
name: kubia # 容器命名
imagePullPolicy: Never
ports: # 容器暴露的端口
- containerPort: 8080
protocol: TCP
EOF
使用部署文件创建资源
k create -f kubia-manual-with-labels.yml
6.6.2 查看pod的标签
k get pods --show-labels
k get pods -L creation_method,env
6.6.3 修改pod的标签
pod kubia-manual-v2 的env标签值是prod
, 我们把这个标签的值修改为 debug
修改一个标签的值时,必须指定--overwrite
参数,目的是防止误修改
k label po kubia-manual-v2 env=debug --overwrite
为pod kubia-manual
设置标签
k label pods kubia-manual creation_method=manual env=debug
6.6.4 使用标签来查询 pod
- 查询
creation_method=manual
的pod
k get pods -l creation_method=manual -L creation_method,env
- 查询有
env
标签的 pod
k get pods -l env -L creation_method,env
- 查询
creation_method=manual
并且env=debug
的 pod
k get pods -l creation_method=manual,env=debug -L creation_method,env
- 查询不存在
creation_method
标签的 pod
k get pods -l '!creation_method' -L creation_method,env
其他查询举例:
creation_method!=manual
env in (prod,debug)
env notin (prod,debug)
6.7 将pod部署到指定的命名空间中
部署文件,其中节点选择器nodeSelector
设置了通过标签gpu=true
来选择节点
cat <<EOF > kubia-gpu.yml
apiVersion: v1
kind: Pod
metadata:
name: kubia-gpu # pod名
spec:
nodeSelector: # 节点选择器,把pod部署到匹配的节点
gpu: "true" # 通过标签 gpu=true 来选择匹配的节点
containers: # 容器配置
- image: luksa/kubia # 镜像
name: kubia # 容器名
imagePullPolicy: Never
EOF
k create -f kubia-gpu.yml
k get pods
我们不能直接指定服务器的地址来约束pod部署的节点
通过为node设置标签,在部署pod时,使用节点选择器,来选择把pod部署到匹配的节点服务器
下面为名称为192.168.126.132的节点服务器,添加标签gpu=true
,给节点设置标签后,容器开始启动
k label no 192.168.126.132 gpu=true
6.8 命名空间
6.8.1 查看命名空间
# 查看命名空间
k get ns
#查看命名空间下的容器
k get pods -n kube-system
6.8.2 创建命名空间
新建部署文件custom-namespace.yml
,创建命名空间,命名为custom-namespace
cat <<EOF > custom-namespace.yml
apiVersion: v1
kind: Namespace
metadata:
name: custom-namespace
EOF
# 创建命名空间
k create -f custom-namespace.yml
k get ns
6.8.3 将pod部署到指定的命名空间中
创建pod,并将其部署到命名空间custom-namespace
# 创建 Pod 时指定命名空间
k create -f kubia-manual.yml -n custom-namespace
# 默认访问default命名空间,默认命名空间中不存在pod kubia-manual
k get po kubia-manual
# 访问custom-namespace命名空间中的pod
k get po kubia-manual -n custom-namespace
6.9 删除pods
# 按名称删除, 可以指定多个名称
# 例如: k delete po po1 po2 po3
k delete po kubia-gpu
# 按标签删除
k delete po -l creation_method=manual
# 删除命名空间和其中所有的pod
k delete ns custom-namespace
# 删除当前命名空间中所有pod
k delete po --all
# 删除工作空间中所有类型中的所有资源
# 这个操作会删除一个系统Service kubernetes,它被删除后会立即被自动重建
k delete all --all
6.10 存活探针
有三种存活探针:
-
HTTP GET
: 返回 2xx 或 3xx 响应码则认为探测成功 -
TCP
:与指定端口建立 TCP 连接,连接成功则为成功 -
Exec
: 在容器内执行任意的指定命令,并检查命令的退出码,退出码为0则为探测成功
6.10.1 HTTP GET 存活探针
在kubia-unhealthy镜像中,应用程序作了这样的设定: 从第6
次请求开始会返回500错
在部署文件中,我们添加探针,来探测容器的健康状态.
探针默认每10秒探测一次,连续三次探测失败后重启容器
cat <<EOF > kubia-liveness-probe.yml
apiVersion: v1
kind: Pod
metadata:
name: kubia-liveness # pod名称
spec:
containers:
- image: luksa/kubia-unhealthy # 镜像
name: kubia # 容器名
imagePullPolicy: Never
livenessProbe: # 存活探针配置
httpGet: # HTTP GET 类型的存活探针
path: / # 探测路径
port: 8080 # 探测端口
EOF
k create -f kubia-liveness-probe.yml
# pod的RESTARTS属性,每过1分半种就会加1
k get po kubia-liveness
查看pod描述
k describe po kubia-liveness
-
delay
: 0表示容器启动后立即开始探测 -
timeout
: 1表示必须在1秒内响应,否则视为探测失败 -
period
:10s表示每10秒探测一次 -
failure
: 3表示连续3次失败后重启容器
通过设置 delay 延迟时间,可以避免在容器内应用没有完全启动的情况下就开始探测
cat <<EOF > kubia-liveness-probe-initial-delay.yml
apiVersion: v1
kind: Pod
metadata:
name: kubia-liveness
spec:
containers:
- image: luksa/kubia-unhealthy
name: kubia
imagePullPolicy: Never
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 15 # 第一次探测的延迟时间
EOF
7.ReplicationController
RC可以自动化维护多个pod,只需指定pod副本的数量,就可以轻松实现自动扩容缩容
当一个pod宕机,RC可以自动关闭pod,并启动一个新的pod替代它
下面是一个RC的部署文件,设置启动三个kubia容器:
cat <<EOF > kubia-rc.yml
apiVersion: v1
kind: ReplicationController # 资源类型
metadata:
name: kubia # 为RC命名
spec:
replicas: 3 # pod副本的数量
selector: # 选择器,用来选择RC管理的pod
app: kubia # 选择标签'app=kubia'的pod,由当前RC进行管理
template: # pod模板,用来创建新的pod
metadata:
labels:
app: kubia # 指定pod的标签
spec:
containers: # 容器配置
- name: kubia # 容器名
image: luksa/kubia # 镜像
imagePullPolicy: Never
ports:
- containerPort: 8080 # 容器暴露的端口
EOF
7.1 创建RC
RC创建后,会根据指定的pod数量3,自动创建3个pod
k create -f kubia-rc.yml
k get rc
k get po -o wide
7.2 修改pod标签
RC是通过指定的标签app=kubia对匹配的pod进行管理的
允许在pod上添加任何其他标签,而不会影响pod与RC的关联关系
k label pod kubia-267nv type=special
k get po --show-labels
但是,如果改变pod的app标签的值,就会使这个pod脱离RC的管理,这样RC会认为这里少了一个pod,那么它会立即创建一个新的pod,来满足我们设置的3个pod的要求
k label pod kubia-fmtkw app=foo --overwrite
k get pods -L app
7.3 修改 pod 模板
pod模板修改后,只影响后续新建的pod,已创建的pod不会被修改
可以删除旧的pod,用新的pod来替代
k edit rc kubia
# 通过RC,把pod扩容到6个
# 可以使用前面用过的scale命令来扩容
# k scale rc kubia --replicas=6
# 或者,可以编辑修改RC的replicas属性,修改成6
k edit rc kubia
7.4 删除RC
删除rc
k delete rc kubia --cascade=false
--cascade=false
:删除rc但不删除容器
8. ReplicaSet
ReplicaSet 被设计用来替代 ReplicationController,它提供了更丰富的pod选择功能.
以后我们总应该使用 RS, 而不适用 RC, 但在旧系统中仍会使用 RC.
cat <<EOF > kubia-replicaset.yml
apiVersion: apps/v1 # RS 是 apps/v1中提供的资源类型
kind: ReplicaSet # 资源类型
metadata:
name: kubia # RS 命名为 kubia
spec:
replicas: 3 # pod 副本数量
selector:
matchLabels: # 使用 label 选择器
app: kubia # 选取标签是 "app=kubia" 的pod
template:
metadata:
labels:
app: kubia # 为创建的pod添加标签 "app=kubia"
spec:
containers:
- name: kubia # 容器名
image: luksa/kubia # 镜像
imagePullPolicy: Never
EOF
8.1 创建 ReplicaSet
k create -f kubia-replicaset.yml
# 之前脱离管理的pod被RS管理
# 设置的pod数量是3,多出的pod会被关闭
k get rs
# 多出的3个pod会被关闭
k get pods --show-labels
8.2 标签选择器
cat <<EOF > kubia-replicaset.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: kubia
spec:
replicas: 4
selector:
matchExpressions: # 表达式匹配选择器
- key: app # label 名是 app
operator: In # in 运算符
values: # label 值列表
- kubia
- foo
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: luksa/kubia
imagePullPolicy: Never
EOF
# 先删除现有 RS
k delete rs kubia --cascade=false
# 再创建 RS
k create -f kubia-replicaset.yml
# 查看rs
k get rs
# 查看pod
k get po --show-labels
可使用的运算符:
-
In
:label与其中一个值匹配 -
NotIn
: label与任何一个值都不匹配 -
Exists
:包含指定label名称(值任意) -
DoesNotExists
:不包含指定的label
清空所有
k delete all --all
9. 特殊控制器
9.1 DaemonSet
在每个节点上运行一个 pod,例如资源监控,kube-proxy等
DaemonSet不指定pod数量,它会在每个节点上部署一个pod
cat <<EOF > ssd-monitor-daemonset.yml
apiVersion: apps/v1
kind: DaemonSet # 资源类型
metadata:
name: ssd-monitor # DS资源命名
spec:
selector:
matchLabels: # 标签匹配器
app: ssd-monitor # 匹配的标签
template:
metadata:
labels:
app: ssd-monitor # 创建pod时,添加标签
spec:
containers: # 容器配置
- name: main # 容器命名
image: luksa/ssd-monitor # 镜像
imagePullPolicy: Never
EOF
9.1.1 创建 DS
DS 创建后,会在所有节点上创建pod,包括master
k create -f ssd-monitor-daemonset.yml
k get po -o wide
可以在所有选定的节点上部署pod
通过节点的label来选择节点
cat <<EOF > ssd-monitor-daemonset.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ssd-monitor
spec:
selector:
matchLabels:
app: ssd-monitor
template:
metadata:
labels:
app: ssd-monitor
spec:
nodeSelector: # 节点选择器
disk: ssd # 选择的节点上具有标签: 'disk=ssd'
containers:
- name: main
image: luksa/ssd-monitor
imagePullPolicy: Never
EOF
k create -f ssd-monitor-daemonset.yml
查看 DS 和 pod, 看到并没有创建pod,这是因为不存在具有disk=ssd
标签的节点
为节点’192.168.126.132’设置标签 disk=ssd
,这样 DS 会在该节点上立即创建 pod
9.2 Job
Job 用来运行单个任务,任务结束后pod不再重启
cat <<EOF > exporter.yml
apiVersion: batch/v1 # Job资源在batch/v1版本中提供
kind: Job # 资源类型
metadata:
name: batch-job # 资源命名
spec:
template:
metadata:
labels:
app: batch-job # pod容器标签
spec:
restartPolicy: OnFailure # 任务失败时重启
containers:
- name: main # 容器名
image: luksa/batch-job # 镜像
imagePullPolicy: Never
EOF
9.2.1 执行一次
创建 job,镜像 batch-job 中的进程,运行120
秒后会自动退出
k create -f exporter.yml
k get job
k get po
等待两分钟后,pod中执行的任务退出,再查看job和pod
9.2.2 执行5次,每次执行1个
使用Job让pod连续运行5次
先创建第一个pod,等第一个完成后后,再创建第二个pod,以此类推,共顺序完成5个pod
cat <<EOF > multi-completion-batch-job.yml
apiVersion: batch/v1
kind: Job
metadata:
name: multi-completion-batch-job
spec:
completions: 5 # 指定完整的数量
template:
metadata:
labels:
app: batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
imagePullPolicy: Never
EOF
k create -f multi-completion-batch-job.yml
9.2.3 执行5次,每次执行2个
共完成5个pod,并每次可以同时启动两个pod
cat <<EOF > multi-completion-parallel-batch-job.yml
apiVersion: batch/v1
kind: Job
metadata:
name: multi-completion-parallel-batch-job
spec:
completions: 5 # 共完成5个
parallelism: 2 # 可以有两个pod同时执行
template:
metadata:
labels:
app: batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
imagePullPolicy: Never
EOF
k create -f multi-completion-parallel-batch-job.yml
9.3 Cronjob
9.3.1 创建cronjob
定时和重复执行的任务
cron时间表格式: “分钟 小时 每月的第几天 月 星期几
”
cat <<EOF > cronjob.yml
apiVersion: batch/v1beta1 # api版本
kind: CronJob # 资源类型
metadata:
name: batch-job-every-fifteen-minutes
spec:
# 0,15,30,45 - 分钟
# 第一个* - 每个小时
# 第二个* - 每月的每一天
# 第三个* - 每月
# 第四个* - 每一周中的每一天
schedule: "0,15,30,45 * * * *"
jobTemplate:
spec:
template:
metadata:
labels:
app: periodic-batch-job
spec:
restartPolicy: OnFailure
containers:
- name: main
image: luksa/batch-job
imagePullPolicy: Never
EOF
k create -f cronjob.yml
10. Service
10.1 service
通过Service资源,为多个pod提供一个单一不变的接入地址
cat <<EOF > kubia-svc.yml
apiVersion: v1
kind: Service # 资源类型
metadata:
name: kubia # 资源命名
spec:
ports:
- port: 80 # Service向外暴露的端口
targetPort: 8080 # 容器的端口
selector:
app: kubia # 通过标签,选择名为kubia的所有pod
EOF
k create -f kubia-svc.yml
从内部网络访问Service
执行curl http://10.68.148.104
来访问Service
执行多次会看到,Service会在多个pod中轮训发送请求
10.2 endpoint
endpoint是在Service和pod之间的一种资源,一个endpoint资源,包含一组pod的地址列表
# 查看kubia服务的endpoint
k describe svc kubia
k get ep
# 查看名为kubia的endpoint
k get ep kubia
10.2.2 创建endpoint
创建endpoint关联到Service,它的名字必须与Service同名
cat <<EOF > external-service-endpoints.yml
apiVersion: v1
kind: Endpoints # 资源类型
metadata:
name: external-service # 名称要与Service名相匹配
subsets:
- addresses: # 包含的地址列表
- ip: 120.52.99.224 # 中国联通的ip地址
- ip: 117.136.190.162 # 中国移动的ip地址
ports:
- port: 80 # 目标服务的的端口
EOF
# 创建Endpoint
k create -f external-service.yml
k describe svc external-service
创建endpoint关联到Service,它的名字必须与Service同名
cat <<EOF > external-service-endpoints.yml
apiVersion: v1
kind: Endpoints # 资源类型
metadata:
name: external-service # 名称要与Service名相匹配
subsets:
- addresses: # 包含的地址列表
- ip: 120.52.99.224 # 中国联通的ip地址
- ip: 117.136.190.162 # 中国移动的ip地址
ports:
- port: 80 # 目标服务的的端口
EOF
# 创建Endpoint
k create -f external-service-endpoints.yml
# 进入一个pod容器
k exec -it kubia-k66lz bash
# 访问 external-service
# 多次访问,会在endpoints地址列表中轮训请求
curl http://external-service
10.3 服务暴露给客户端
前面创建的Service只能在集群内部网络中访问,那么怎么让客户端来访问Service呢?
三种方式
-
NodePort
:每个节点都开放一个端口 -
LoadBalance
:NodePort的一种扩展,负载均衡器需要云基础设施来提供 Ingress
10.3.1 NodePort
在每个节点(包括master),都开放一个相同的端口,可以通过任意节点的端口来访问Service
cat <<EOF > kubia-svc-nodeport.yml
apiVersion: v1
kind: Service
metadata:
name: kubia-nodeport
spec:
type: NodePort # 在每个节点上开放访问端口
ports:
- port: 80 # 集群内部访问该服务的端口
targetPort: 8080 # 容器的端口
nodePort: 30123 # 外部访问端口
selector:
app: kubia
EOF
k create -f kubia-svc-nodeport.yml
k get svc kubia-nodeport
可以通过任意节点的30123
端口来访问 Service
http://192.168.126.131:30123
http://192.168.126.132:30123
11. 磁盘挂载到容器
11.1 卷
卷的类型:
-
emptyDir
: 简单的空目录,随容器删除而删除 -
hostPath
: 工作节点中的磁盘路径 -
gitRepo
: 从git克隆的本地仓库 -
nfs
: nfs共享文件系统
11.1.1 emptyDir
- 创建包含两个容器的pod, 它们共享同一个卷
cat <<EOF > fortune-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: fortune
labels:
app: fortune
spec:
containers:
- image: luksa/fortune # 镜像名
name: html-genrator # 容器名
imagePullPolicy: Never
volumeMounts:
- name: html # 卷名为 html
mountPath: /var/htdocs # 容器中的挂载路径
- image: nginx:alpine # 第二个镜像名
name: web-server # 第二个容器名
imagePullPolicy: Never
volumeMounts:
- name: html # 相同的卷 html
mountPath: /usr/share/nginx/html # 在第二个容器中的挂载路径
readOnly: true # 设置为只读
ports:
- containerPort: 80
protocol: TCP
volumes: # 卷
- name: html # 为卷命名
emptyDir: {} # emptyDir类型的卷
EOF
k create -f fortune-pod.yml
k get po
- 创建Service, 通过这个Service访问pod的80端口
cat <<EOF > fortune-svc.yml
apiVersion: v1
kind: Service
metadata:
name: fortune
spec:
type: NodePort
ports:
- port: 8088
targetPort: 80
nodePort: 38088
selector:
app: fortune
EOF
k create -f fortune-svc.yml
k get svc
11.1.2 nfs
在 master 节点192.168.126.131
上创建 nfs 目录 /etc/nfs_data
,
并允许 `192.168.126.0 网段的主机共享访问这个目录
# 创建文件夹
mkdir /etc/nfs_data
# 在exports文件夹中写入配置
# no_root_squash: 服务器端使用root权限
cat <<EOF > /etc/exports
/etc/nfs_data 192.168.126.0/24(rw,async,no_root_squash)
EOF
systemctl enable nfs
systemctl enable rpcbind
systemctl start nfs
systemctl start rpcbind
尝试在客户端主机上,例如192.168.126.132
,挂载远程的nfs目录
# 新建挂载目录
mkdir /etc/web_dir/
# 在客户端, 挂载服务器的 nfs 目录
mount -t nfs 192.168.126.131:/etc/nfs_data /etc/web_dir/
- 持久化存储
创建PersistentVolume
- 持久卷资源
cat <<EOF > mongodb-pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-pv
spec:
capacity:
storage: 1Gi # 定义持久卷大小
accessModes:
- ReadWriteOnce # 只允许被一个客户端挂载为读写模式
- ReadOnlyMany # 可以被多个客户端挂载为只读模式
persistentVolumeReclaimPolicy: Retain # 当声明被释放,持久卷将被保留
nfs: # nfs远程目录定义
path: /etc/nfs_data
server: 192.168.126.131
EOF
# 创建持久卷
k create -f mongodb-pv.yml
# 查看持久卷
k get pv
- 持久卷声明
使用持久卷声明,使应用与底层存储技术解耦
cat <<EOF > mongodb-pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-pvc
spec:
resources:
requests:
storage: 1Gi # 申请1GiB存储空间
accessModes:
- ReadWriteOnce # 允许单个客户端读写
storageClassName: "" # 参考动态配置章节
EOF
k create -f mongodb-pvc.yml
k get pvc
- 启动mongodb容器
cat <<EOF > mongodb-pod-pvc.yml
apiVersion: v1
kind: Pod
metadata:
name: mongodb
spec:
containers:
- image: mongo
name: mongodb
imagePullPolicy: Never
securityContext:
runAsUser: 0
volumeMounts:
- name: mongodb-data
mountPath: /data/db
ports:
- containerPort: 27017
protocol: TCP
volumes:
- name: mongodb-data
persistentVolumeClaim:
claimName: mongodb-pvc # 引用之前创建的"持久卷声明"
EOF
12. 配置启动参数
12.1 docker 的命令行参数
Dockerfile
中定义命令和参数的指令
-
ENTRYPOINT
启动容器时,在容器内执行的命令 -
CMD
对启动命令传递的参数
CMD
可以在docker run命令中进行覆盖
例如:
......
ENTRYPOINT ["java", "-jar", "/opt/sp05-eureka-0.0.1-SNAPSHOT.jar"]
CMD ["--spring.profiles.active=eureka1"]
12.2 k8s中覆盖docker的ENTRYPOINT和CMD
command
可以覆盖ENTRYPOINT
args
可以覆盖CMD
在镜像luksa/fortune:args
中,设置了自动生成内容的间隔时间参数为10
秒
......
CMD ["10"]
可以通过k8s的args
来覆盖docker的CMD
cat <<EOF > fortune-pod-args.yml
apiVersion: v1
kind: Pod
metadata:
name: fortune
labels:
app: fortune
spec:
containers:
- image: luksa/fortune:args
args: ["2"] # docker镜像中配置的CMD是10,这里用args把这个值覆盖成2
name: html-genrator
imagePullPolicy: Never
volumeMounts:
- name: html
mountPath: /var/htdocs
- image: nginx:alpine
name: web-server
imagePullPolicy: Never
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
volumes:
- name: html
emptyDir: {}
EOF
k create -f fortune-pod-args.yml
# 查看pod
k get po -o wide
重复地执行curl命令,访问该pod,会看到数据每2秒刷新一次
12.3 环境变量
在镜像luksa/fortune:env
中通过环境变量INTERVAL
来指定内容生成的间隔时间
下面配置中,通过env配置,在容器中设置了环境变量INTERVAL
的值
cat <<EOF > fortune-pod-env.yml
apiVersion: v1
kind: Pod
metadata:
name: fortune
labels:
app: fortune
spec:
containers:
- image: luksa/fortune:env
env: # 设置环境变量 INTERVAL=5
- name: INTERVAL
value: "5"
name: html-genrator
imagePullPolicy: Never
volumeMounts:
- name: html
mountPath: /var/htdocs
- image: nginx:alpine
name: web-server
imagePullPolicy: Never
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
volumes:
- name: html
emptyDir: {}
EOF
k create -f fortune-pod-env.yml
# 查看pod
k get po -o wide
k exec -it fortune bash
env
重复地执行curl命令,访问该pod,会看到数据每5秒刷新一次
12.4 ConfigMap
通过ConfigMap资源,可以从pod中把环境变量配置分离出来,是环境变量配置与pod解耦
- 可以从命令行创建ConfigMap资源:
# 直接命令行创建
k create configmap fortune-config --from-literal=sleep-interval=20
- 或者从部署文件创建ConfigMap:
# 或从文件创建
cat <<EOF > fortune-config.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: fortune-config
data:
sleep-interval: "10"
EOF
# 创建ConfigMap
k create -f fortune-config.yml
# 查看ConfigMap的配置
k get cm fortune-config -o yaml
- 从
ConfigMap
获取配置数据,设置为pod的环境变量
cat <<EOF > fortune-pod-env-configmap.yml
apiVersion: v1
kind: Pod
metadata:
name: fortune
labels:
app: fortune
spec:
containers:
- image: luksa/fortune:env
imagePullPolicy: Never
env:
- name: INTERVAL # 环境变量名
valueFrom:
configMapKeyRef: # 环境变量的值从ConfigMap获取
name: fortune-config # 使用的ConfigMap名称
key: sleep-interval # 用指定的键从ConfigMap取数据
name: html-genrator
volumeMounts:
- name: html
mountPath: /var/htdocs
- image: nginx:alpine
imagePullPolicy: Never
name: web-server
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
volumes:
- name: html
emptyDir: {}
EOF
13 Deployment
Deployment
是一种更高级的资源,用于部署或升级应用.
创建Deployment
时,ReplicaSet
资源会随之创建,实际Pod是由ReplicaSet
创建和管理,而不是由Deployment
直接管理
Deployment
可以在应用滚动升级过程中, 引入另一个RepliaSet
, 并协调两个ReplicaSet
.
cat <<EOF > kubia-deployment-v1.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: kubia
spec:
replicas: 3
selector:
matchLabels:
app: kubia
template:
metadata:
name: kubia
labels:
app: kubia
spec:
containers:
- image: luksa/kubia:v1
imagePullPolicy: Never
name: nodejs
EOF
k create -f kubia-deployment-v1.yml --record
k get deploy
k rollout status deploy kubia
13.1 升级 Deployment
只需要在 pod 模板中修改镜像的 Tag, Deployment 就可以自动完成升级过程
Deployment的升级策略
- 滚动升级 Rolling Update - 渐进的删除旧的pod, 同时创建新的pod, 这是默认的升级策略
- 重建 Recreate - 一次删除所有旧的pod, 再重新创建新的pod
minReadySeconds设置为10秒, 减慢滚动升级速度, 便于我们观察升级的过程.minReadySeconds
设置为10秒, 减慢滚动升级速度, 便于我们观察升级的过程.
k patch deploy kubia -p '{"spec": {"minReadySeconds": 10}}'
触发滚动升级
修改 Deployment 中 pod 模板使用的镜像就可以触发滚动升级
为了便于观察, 在另一个终端中执行循环, 通过 service 来访问pod
while true; do curl http://192.168.126.131:30123; sleep 0.5s; done
k set image deploy kubia nodejs=luksa/kubia:v2
通过不同的命令来了解升级的过程和原理
# 查看滚动升级的状态
k rollout status deploy kubia
k get rs
k get po --show-labels
k describe rs kubia-66b4657d7b
13.2 回滚 Deployment
luksa/kubia:v3 镜像中的应用模拟一个 bug, 从第5次请求开始, 会出现 500 错误
k set image deploy kubia nodejs=luksa/kubia:v3
# 手动回滚到上一个版本
k rollout undo deploy kubia
13.3 控制滚动升级速率
滚动升级时
- 先创建新版本pod
- 再销毁旧版本pod
可以通过参数来控制, 每次新建的pod数量和销毁的pod数量:
-
maxSurge
- 默认25%
,允许超出的 pod 数量.
如果期望pod数量是4, 滚动升级期间, 最多只允许实际有5个 pod. -
maxUnavailable
- 默认25%
,允许有多少 pod 处于不可用状态.
如果期望pod数量是4, 滚动升级期间, 最多只允许 1 个 pod 不可用, 也就是说任何时间都要保持至少有 3 个可用的pod.
查看参数
k get deploy -o yaml
13.4 暂停滚动升级
将 image 升级到 v4 版本触发更新, 并立即暂停更新.
这时会有一个新版本的 pod 启动, 可以暂停更新过程, 让少量用户可以访问到新版本, 并观察其运行是否正常.
根据新版本的运行情况, 可以继续完成更新, 或回滚到旧版本.
k set image deploy kubia nodejs=luksa/kubia:v4
# 暂停
k rollout pause deploy kubia
# 继续
k rollout resume deploy kubia
13.5 自动阻止出错版本升级
minReadySeconds
- 新创建的pod成功运行多久后才,继续升级过程
- 在该时间段内, 如果容器的就绪探针返回失败, 升级过程将被阻止
修改Deployment
配置,添加就绪探针
cat <<EOF > kubia-deployment-v3-with-readinesscheck.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: kubia
spec:
replicas: 3
selector:
matchLabels:
app: kubia
minReadySeconds: 10
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
name: kubia
labels:
app: kubia
spec:
containers:
- image: luksa/kubia:v3
name: nodejs
imagePullPolicy: Never
readinessProbe:
periodSeconds: 1
httpGet:
path: /
port: 8080
EOF
k apply -f kubia-deployment-v3-with-readinesscheck.yml
就绪探针探测间隔设置成了 1 秒, 第5次请求开始每次请求都返回500错, 容器会处于未就绪状态.minReadySeconds
被设置成了10秒, 只有pod就绪10秒后, 升级过程才会继续.所以这是滚动升级过程会被阻塞, 不会继续进行.
默认升级过程被阻塞10分钟后, 升级过程会被视为失败, Deployment描述中会显示超时(ProgressDeadlineExceeded).
k describe deploy kubia
这是只能通过手动执行 rollout undo 命令进行回滚
k rollout undo deploy kubia
14. Dashboard 仪表盘
14.1 查看 Dashboard 部署信息
# 查看pod
k get pod -n kube-system | grep dashboard
# 查看service
k get svc -n kube-system | grep dashboard
# 查看集群信息
k cluster-info | grep dashboar
根据上面信息可以看到 dashboard 的访问地址:
https://192.168.126.131:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy
现在访问 dashboard 由于安全设置的原因无法访问
14.2 证书验证访问
使用集群CA 生成客户端证书,该证书拥有所有权限
cd /etc/kubernetes/ssl
# 导出证书文件
openssl pkcs12 -export -in admin.pem -inkey admin-key.pem -out kube-admin.p12
下载 /etc/kubernetes/ssl/kube-admin.p12
证书文件, 在浏览器中导入:
14.3 令牌
# 创建Service Account 和 ClusterRoleBinding
k apply -f /etc/ansible/manifests/dashboard/admin-user-sa-rbac.yaml
# 获取 Bearer Token,复制输出中 ‘token:’ 开头那一行
k -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')